Browse Source

修改上传

yangg 3 tháng trước cách đây
mục cha
commit
8b9c4dedbb
3 tập tin đã thay đổi với 230 bổ sung45 xóa
  1. 1 1
      .env.development
  2. 23 8
      src/views/digitalHuman/list/crud.tsx
  3. 206 36
      src/views/digitalHuman/list/index.vue

+ 1 - 1
.env.development

@@ -6,7 +6,7 @@ ENV = 'development'
 # 本地环境接口地址 121.36.251.245
 
 
-VITE_API_URL = 'http://192.168.66.187:8083'
+VITE_API_URL = 'https://backend.qicai321.com'
 # VITE_API_URL = 'https://backend.qicai321.com'
 VITE_API_WX_URL='https://api.weixin.qq.com/'
 

+ 23 - 8
src/views/digitalHuman/list/crud.tsx

@@ -4,7 +4,7 @@ import { dictionary } from '/@/utils/dictionary';
 import { successMessage } from '/@/utils/message';
 import { auth } from '/@/utils/authFunction';
 import tableSelector from '/@/components/tableSelector/index.vue';
-import { shallowRef } from 'vue';
+import { shallowRef, getCurrentInstance } from 'vue';
 import { useRouter } from 'vue-router';
 import { Plus } from '@element-plus/icons-vue';
 
@@ -63,18 +63,21 @@ export const createCrudOptions = function ({ crudExpose }: CreateCrudOptionsProp
 			actionbar: {
 				buttons: {
 					add: {
-						show: true//auth('digitalHuma:Create'),
+						show: true,
+						click: () => {
+							crudExpose.emit('add-digital-human');
+						}
 					},
 				},
 			},
 			rowHandle: {
 				//固定右侧
 				fixed: 'right',
-				width: 200,
+				width: 300,
 				buttons: {
 					view: {
 						iconRight: 'view',
-						show: true,
+						show: false,
 						type: 'text',
 						click: ({ row }) => {
 							// 查看数字人详情
@@ -87,16 +90,17 @@ export const createCrudOptions = function ({ crudExpose }: CreateCrudOptionsProp
 					edit: {
 						iconRight: 'Edit',
 						type: 'text',
-						show: true,//auth('digitalHuma:Update'),
+						show: false,
 						/* click: ({ row }) => {
-							// 直接使用emit触发事件
-							crudExpose.emit('edit-digital-human', row);
+							console.log(crudExpose);
+					
+							//crudExpose.emit('edit-digital-human', row);
 						} */
 					},
 					remove: {
 						iconRight: 'Delete',
 						type: 'text',
-						show: true//	auth('digitalHuma:Delete'),
+						show: false//	auth('digitalHuma:Delete'),
 					},
 				},
 			},
@@ -382,6 +386,17 @@ export const createCrudOptions = function ({ crudExpose }: CreateCrudOptionsProp
 						show: false,
 					},
 				},
+			/* 	operation: {
+					title: '操作',
+					type: 'button',
+					width: '200px',
+					buttons: {
+						edit: {
+							show: false
+						},
+					},
+					columnSlot: true
+				} */
 			},
 		},
 	};

+ 206 - 36
src/views/digitalHuman/list/index.vue

@@ -4,19 +4,80 @@
 		<div class="digital-human-container">
 			<!-- 左侧列表区域 -->
 			<div class="list-area">
-				<fs-crud ref="crudRef" v-bind="crudBinding" @edit-digital-human="openEditForm"> </fs-crud>
+				<fs-crud ref="crudRef" v-bind="crudBinding" @add-digital-human="openAddForm" @edit-digital-human="openEditForm">
+					<!-- 自定义行操作按钮 -->
+					<template #cell-rowHandle-middle="scope">
+						<!-- 查看按钮 -->
+						<el-button 
+							size="small" 
+							type="text" 
+							@click="openViewForm(scope.row)"
+						>
+							查看<el-icon><View /></el-icon>
+						</el-button>
+						
+						<!-- 编辑按钮 -->
+						<el-button 
+							size="small" 
+							type="text" 
+							@click="openEditForm(scope.row)"
+						>
+							编辑<el-icon><Edit /></el-icon>
+						</el-button>
+						
+						<!-- 删除按钮 -->
+						<el-button 
+							size="small" 
+							type="text" 
+							@click="handleDelete(scope.row)"
+							class="text-danger"
+						>
+							删除<el-icon><Delete /></el-icon>
+						</el-button>
+					</template>
+				</fs-crud>
 			</div>
 			
 			<!-- 将侧边栏表单改为弹窗 -->
 			<el-dialog
 				v-model="showForm"
-				:title="formMode === 'add' ? '新增数字人' : '编辑数字人'"
+				:title="getDialogTitle()"
 				width="500px"
 				:close-on-click-modal="false"
 				:destroy-on-close="true"
 			>
-				<!-- 添加表单内容 -->
-				<el-form ref="formRef" :model="formData" label-width="100px" class="form-content">
+				<!-- 查看模式使用 el-descriptions 展示数据 -->
+				<el-descriptions v-if="formMode === 'view'" :column="1" border>
+					<el-descriptions-item label="名称">{{ formData.name }}</el-descriptions-item>
+					<el-descriptions-item label="头像">
+						<img v-if="formData.avatar_url" :src="formData.avatar_url" class="avatar" />
+						<span v-else>无头像</span>
+					</el-descriptions-item>
+					<el-descriptions-item label="模板视频">
+						<video 
+							v-if="formData.template_video_url" 
+							:src="formData.template_video_url" 
+							class="video-preview" 
+							controls>
+						</video>
+						<span v-else>无视频</span>
+					</el-descriptions-item>
+					<el-descriptions-item label="状态">
+						<el-tag :type="formData.status === 1 ? 'success' : 'info'">
+							{{ formData.status === 1 ? '启用' : '禁用' }}
+						</el-tag>
+					</el-descriptions-item>
+					<el-descriptions-item label="语音ID">
+						{{ getVoiceName(formData.config.voice_id) }}
+					</el-descriptions-item>
+					<el-descriptions-item label="风格">
+						{{ getStyleName(formData.config.style) }}
+					</el-descriptions-item>
+					<el-descriptions-item label="描述">{{ formData.description || '无' }}</el-descriptions-item>
+				</el-descriptions>
+
+				<!-- 添加/编辑表单内容 -->
+				<el-form v-else ref="formRef" :model="formData" label-width="100px" class="form-content">
 					<el-form-item label="名称" prop="name" :rules="[{ required: true, message: '请输入名称', trigger: 'blur' }]">
 						<el-input v-model="formData.name" placeholder="请输入数字人名称"></el-input>
 					</el-form-item>
@@ -91,8 +152,8 @@
 				
 				<template #footer>
 					<div class="dialog-footer">
-						<el-button @click="closeForm">取消</el-button>
-						<el-button type="primary" @click="submitForm">提交</el-button>
+						<el-button @click="closeForm">{{ formMode === 'view' ? '关闭' : '取消' }}</el-button>
+						<el-button v-if="formMode !== 'view'" type="primary" @click="submitForm">提交</el-button>
 					</div>
 				</template>
 			</el-dialog>
@@ -104,11 +165,11 @@
 import { onMounted, ref, reactive } from 'vue';
 import { useFs } from '@fast-crud/fast-crud';
 import { createCrudOptions } from './crud';
-import { GetPermission, AddObj, UpdateObj } from './api';
+import { GetPermission, AddObj, UpdateObj, DelObj } from './api';
 import * as api from './api';  // Import the full api module
 import { handleColumnPermission } from '/@/utils/columnPermission';
-import { ElMessage } from 'element-plus';
-import { Close, Plus } from '@element-plus/icons-vue';
+import { ElMessage, ElMessageBox } from 'element-plus';
+import { Close, Plus, Edit, Delete, View } from '@element-plus/icons-vue';
 import { Session } from '/@/utils/storage';
 
 const apiBaseUrl = import.meta.env.VITE_API_URL;
@@ -118,7 +179,7 @@ const { crudBinding, crudRef, crudExpose, crudOptions, resetCrudOptions } = useF
 // 表单模式:add 或 edit
 const formMode = ref('add');
 const showForm = ref(false);
-const formData = ref({
+const defaultFormData = {
 	name: '',
 	description: '',
 	avatar_url: '',
@@ -128,7 +189,9 @@ const formData = ref({
 		voice_id: 'xiaoming_voice_premium',
 		style: 'professional'
 	}
-});
+};
+
+const formData = ref({...defaultFormData});
 
 // Add formRef reference
 const formRef = ref();
@@ -136,33 +199,53 @@ const formRef = ref();
 // 打开添加表单
 const openAddForm = () => {
 	formMode.value = 'add';
-	formData.value = {
-		name: '',
-		description: '',
-		avatar_url: '',
-		status: 1,
-		template_video_url: '',
-		config: {
-			voice_id: 'xiaoming_voice_premium',
-			style: 'professional'
-		}
-	};
+	formData.value = {...defaultFormData};
 	showForm.value = true;
 };
 
 // 打开编辑表单
 const openEditForm = (row: any) => {
+	console.log('编辑行数据:', row);
 	formMode.value = 'edit';
-	formData.value = JSON.parse(JSON.stringify(row)); // 深拷贝
+	// 深拷贝行数据
+	const rowData = JSON.parse(JSON.stringify(row));
 	
-	// 确保config对象存在
-	if (!formData.value.config) {
-		formData.value.config = {
-			voice_id: 'xiaoming_voice_premium',
-			style: 'professional'
-		};
+	// 确保 config 是对象格式
+	if (typeof rowData.config === 'string') {
+		try {
+			rowData.config = JSON.parse(rowData.config);
+		} catch (e) {
+			console.error('解析config失败:', e);
+			rowData.config = {...defaultFormData.config};
+		}
+	} else if (!rowData.config) {
+		rowData.config = {...defaultFormData.config};
 	}
 	
+	formData.value = rowData;
+	showForm.value = true;
+};
+
+// 打开查看表单(只读模式)
+const openViewForm = (row: any) => {
+	console.log('查看行数据:', row);
+	formMode.value = 'view';
+	// 深拷贝行数据
+	const rowData = JSON.parse(JSON.stringify(row));
+	
+	// 确保 config 是对象格式
+	if (typeof rowData.config === 'string') {
+		try {
+			rowData.config = JSON.parse(rowData.config);
+		} catch (e) {
+			console.error('解析config失败:', e);
+			rowData.config = {...defaultFormData.config};
+		}
+	} else if (!rowData.config) {
+		rowData.config = {...defaultFormData.config};
+	}
+	
+	formData.value = rowData;
 	showForm.value = true;
 };
 
@@ -217,21 +300,62 @@ const beforeVideoUpload = (file: any) => {
 const submitForm = async () => {
 	try {
 		await formRef.value.validate();
+		
+		// 处理配置对象
+		const submitData = {...formData.value};
+		if (submitData.config && typeof submitData.config === 'object') {
+			// 确保 config 符合类型要求
+			const config = {
+				voice_id: submitData.config.voice_id || '',
+				style: submitData.config.style || ''
+			};
+			// 将config转为字符串
+			submitData.config = JSON.stringify(config) as any; // 使用类型断言解决类型错误
+		}
+		
+		// 在发送请求前,确保config是字符串类型
 		if (formMode.value === 'add') {
-			await AddObj(formData.value);
+			await AddObj(submitData);
 			ElMessage.success('添加成功');
 		} else {
-			await UpdateObj(formData.value);
+			await UpdateObj(submitData);
 			ElMessage.success('更新成功');
 		}
+		
 		closeForm();
-		// 刷新列表
-		fetchData();
+		crudExpose.doRefresh();
 	} catch (error) {
 		console.error('表单提交错误:', error);
+		ElMessage.error('提交失败,请检查表单信息');
 	}
 };
 
+// 处理删除
+const handleDelete = (row: any) => {
+	ElMessageBox.confirm(
+		`确定要删除数字人 "${row.name}" 吗?`,
+		'删除确认',
+		{
+			confirmButtonText: '确定',
+			cancelButtonText: '取消',
+			type: 'warning',
+		}
+	)
+		.then(async () => {
+			try {
+				await DelObj(row.id);
+				ElMessage.success('删除成功');
+				crudExpose.doRefresh();
+			} catch (error) {
+				console.error('删除失败:', error);
+				ElMessage.error('删除失败,请稍后重试');
+			}
+		})
+		.catch(() => {
+			// 用户取消删除操作
+		});
+};
+
 // Define the fetchData function
 const fetchData = () => {
 	crudExpose.doRefresh();
@@ -254,6 +378,38 @@ onMounted(async () => {
 	// 刷新
 	crudExpose.doRefresh();
 });
+
+// 获取对话框标题
+const getDialogTitle = () => {
+	if (formMode.value === 'add') return '新增数字人';
+	if (formMode.value === 'edit') return '编辑数字人';
+	return '查看数字人';
+};
+
+// 语音ID映射
+const voiceOptions = [
+	{ label: '小明(高级)', value: 'xiaoming_voice_premium' },
+	{ label: '小红', value: 'xiaohong_voice' }
+];
+
+// 风格映射
+const styleOptions = [
+	{ label: '专业', value: 'professional' },
+	{ label: '友好', value: 'friendly' },
+	{ label: '严肃', value: 'serious' }
+];
+
+// 获取语音名称
+const getVoiceName = (voiceId: string) => {
+	const option = voiceOptions.find(item => item.value === voiceId);
+	return option ? option.label : voiceId;
+};
+
+// 获取风格名称
+const getStyleName = (style: string) => {
+	const option = styleOptions.find(item => item.value === style);
+	return option ? option.label : style;
+};
 </script>
 
 <style scoped>
@@ -326,10 +482,11 @@ onMounted(async () => {
 }
 
 .video-preview {
-	width: 100px;
-	height: 100px;
+	width: 200px;
+	height: auto;
+	max-height: 150px;
 	display: block;
-	object-fit: cover;
+	object-fit: contain;
 }
 
 .video-uploader-placeholder {
@@ -338,4 +495,17 @@ onMounted(async () => {
 	border: 1px dashed #d9d9d9;
 	border-radius: 6px;
 }
+
+/* 添加删除按钮的危险样式 */
+.text-danger {
+	color: #F56C6C;
+}
+.text-danger:hover {
+	color: #f78989;
+}
+
+/* 添加查看模式的样式 */
+.el-descriptions {
+	margin-bottom: 20px;
+}
 </style>