3 커밋 e4948a21b2 ... cc7f02146b

작성자 SHA1 메시지 날짜
  zhangchong cc7f02146b reactor:随手拍公告牌新增安全卫士上传视频和视频封面; 1 일 전
  zhangchong dea8a07a81 reactor:523 新增【值班管理】功能;520 来电弹屏增加运营商字段;519 创建知识页面新增“重要政策文件”模板;517 流程管理加导出功能;518 【常用意见管理】增加导出等功能;513 新增【设为观察件】等功能;515 知识库管理增加查询条件;388 智能回访任务查询; 1 일 전
  zhangchong 60d448841a reactor:523 新增【值班管理】功能;520 来电弹屏增加运营商字段;519 创建知识页面新增“重要政策文件”模板;517 流程管理加导出功能;518 【常用意见管理】增加导出等功能;513 新增【设为观察件】等功能;515 知识库管理增加查询条件;388 智能回访任务查询; 1 일 전

+ 4 - 4
src/App.vue

@@ -238,14 +238,14 @@ const setLockScreen = computed(() => {
 });
 
 // 可同时显示的消息最大数量
-const messageConfig = reactive<any>({
+const messageConfig = {
 	max: 3, // 最大数量
 	offset: 70, // 距离顶部的距离
-});
+};
 // 自动在两个中文字符之间插入空格
-const buttonConfig = reactive<any>({
+const buttonConfig = {
 	autoInsertSpace: false,
-});
+};
 // 获取全局组件大小
 const getGlobalComponentSize = computed(() => {
 	return other.globalComponentSize();

+ 21 - 5
src/views/plan/retrieval/index.vue

@@ -26,18 +26,34 @@
 				</pane>
 				<pane class="center-container">
 					<div class="input-box">
-						<el-select v-model="state.queryParams.RetrievalType" placeholder="请选择" class="width120" @change="handleQuery" :disabled="centerLoading">
+						<el-select
+							v-model="state.queryParams.RetrievalType"
+							placeholder="请选择"
+							class="width120"
+							@change="handleQuery"
+							:disabled="centerLoading"
+						>
 							<el-option label="全文" value="0" />
 							<el-option label="标题" value="1" />
 							<el-option label="内容" value="2" />
 						</el-select>
 						<div class="input-with-button w100">
 							<div class="flex">
-								<el-input v-model="state.queryParams.Keyword" placeholder="关键词" clearable class="mr10 w100" @keyup.enter="handleQuery" :disabled="centerLoading"> </el-input>
+								<el-input
+									v-model="state.queryParams.Keyword"
+									placeholder="关键词"
+									clearable
+									class="mr10 w100"
+									@keyup.enter="handleQuery"
+									:disabled="centerLoading"
+								>
+								</el-input>
 								<el-button type="primary" class="btn" :loading="centerLoading" @click="handleQuery"
 									><SvgIcon name="ele-Search" class="mr5" />搜索</el-button
 								>
-								<el-button @click="resetQuery" class="default-button" :loading="centerLoading"> <SvgIcon name="ele-Refresh" class="mr5" />重置</el-button>
+								<el-button @click="resetQuery" class="default-button" :loading="centerLoading">
+									<SvgIcon name="ele-Refresh" class="mr5" />重置</el-button
+								>
 							</div>
 						</div>
 					</div>
@@ -236,10 +252,10 @@ const resetQuery = throttle(() => {
 	state.queryParams.SortField = 'pageView';
 	state.queryParams.Title = null;
 	state.queryParams.Content = null;
-	treeSearchRef.value.setSelected(state.queryParams.PlanTypeID , false); // 清空选择
+	treeSearchRef.value.setSelected(state.queryParams.PlanTypeID, false); // 清空选择
 	treeSearchRef.value.clearKeyword(); // 清空搜索关键词
 	treeSearchRef.value.search(); // 搜索
-  state.queryParams.PlanTypeID = null;
+	state.queryParams.PlanTypeID = null;
 	queryList();
 
 	setTimeout(() => {

+ 4 - 0
src/views/snapshot/config/industry/components/Industry-add.vue

@@ -175,6 +175,7 @@
 							ref="uploadListRefBg"
 							name="fileData"
 							:on-error="onUploadError"
+							accept="image/*"
 						>
 							<img v-if="bgUrl" :src="bgUrl" class="avatar" alt="" />
 							<SvgIcon v-else class="avatar-uploader-icon" name="ele-Plus" size="28px" />
@@ -191,6 +192,7 @@
 							ref="uploadListRefBanner"
 							name="fileData"
 							:on-error="onUploadError"
+							accept="image/*"
 						>
 							<img v-if="bannerUrl" :src="bannerUrl" class="avatar" alt="" />
 							<SvgIcon v-else class="avatar-uploader-icon" name="ele-Plus" size="28px" />
@@ -207,6 +209,7 @@
 							ref="uploadListRefCell"
 							name="fileData"
 							:on-error="onUploadError"
+							accept="image/*"
 						>
 							<img v-if="cellImgUrl" :src="cellImgUrl" class="avatar" alt="" />
 							<SvgIcon v-else class="avatar-uploader-icon" name="ele-Plus" size="28px" />
@@ -223,6 +226,7 @@
 							ref="uploadListRefCareCell"
 							name="fileData"
 							:on-error="onUploadError"
+							accept="image/*"
 						>
 							<img v-if="careCellImgUrl" :src="careCellImgUrl" class="avatar" alt="" />
 							<SvgIcon v-else class="avatar-uploader-icon" name="ele-Plus" size="28px" />

+ 4 - 0
src/views/snapshot/config/industry/components/Industry-edit.vue

@@ -175,6 +175,7 @@
 							ref="uploadListRefBg"
 							name="fileData"
 							:on-error="onUploadError"
+							accept="image/*"
 						>
 							<img v-if="bgUrl" :src="bgUrl" class="avatar" alt="" />
 							<SvgIcon v-else class="avatar-uploader-icon" name="ele-Plus" size="28px" />
@@ -191,6 +192,7 @@
 							ref="uploadListRefBanner"
 							name="fileData"
 							:on-error="onUploadError"
+							accept="image/*"
 						>
 							<img v-if="bannerUrl" :src="bannerUrl" class="avatar" alt="" />
 							<SvgIcon v-else class="avatar-uploader-icon" name="ele-Plus" size="28px" />
@@ -207,6 +209,7 @@
 							ref="uploadListRefCell"
 							name="fileData"
 							:on-error="onUploadError"
+							accept="image/*"
 						>
 							<img v-if="cellImgUrl" :src="cellImgUrl" class="avatar" alt="" />
 							<SvgIcon v-else class="avatar-uploader-icon" name="ele-Plus" size="28px" />
@@ -223,6 +226,7 @@
 							ref="uploadListRefCareCell"
 							name="fileData"
 							:on-error="onUploadError"
+							accept="image/*"
 						>
 							<img v-if="careCellImgUrl" :src="careCellImgUrl" class="avatar" alt="" />
 							<SvgIcon v-else class="avatar-uploader-icon" name="ele-Plus" size="28px" />

+ 219 - 32
src/views/snapshot/info/sspConfig/components/Config-add.vue

@@ -72,7 +72,7 @@
 					</el-form-item>
 				</el-col>
 				<el-col>
-					<el-form-item label="公告标识">
+					<el-form-item label="标识">
 						<el-checkbox v-model="state.ruleForm.isOpen">是否公开</el-checkbox>
 						<el-checkbox v-model="state.ruleForm.isBold">是否加粗</el-checkbox>
 						<el-checkbox v-model="state.ruleForm.isOpenWebsite">网站公开</el-checkbox>
@@ -80,34 +80,90 @@
 						<el-checkbox v-model="state.ruleForm.isWeChat">微信公开</el-checkbox>
 						<el-checkbox v-model="state.ruleForm.isTop">是否置顶</el-checkbox>
 						<el-checkbox v-model="state.ruleForm.isPopup">是否飘窗</el-checkbox>
-						<el-checkbox v-model="state.ruleForm.isSnapshot">是否随手拍</el-checkbox>
-					</el-form-item>
-				</el-col>
-				<el-col>
-					<el-form-item label="志愿者类型" prop="safetyTypes" :rules="[{ required: true, message: '请选择志愿者类型', trigger: 'change' }]">
-						<el-checkbox-group v-model="state.ruleForm.safetyTypes">
-							<el-checkbox :label="item.dicDataName" :value="item.dicDataValue" v-for="item in safetyTypesOptions" :key="item.dicDataValue" />
-						</el-checkbox-group>
-					</el-form-item>
-				</el-col>
-				<el-col>
-					<el-form-item label="公告形式" prop="type" :rules="[{ required: true, message: '请选择公告形式', trigger: 'change' }]">
-						<el-radio-group v-model="state.ruleForm.type">
-							<el-radio value="1">消息</el-radio>
-							<el-radio value="2">视频</el-radio>
-						</el-radio-group>
-					</el-form-item>
-				</el-col>
-				<el-col>
-					<el-form-item label="视频地址" prop="videoPath" :rules="[{ required: false, message: '请填写视频地址', trigger: 'blur' }]">
-						<el-input v-model="state.ruleForm.videoPath" placeholder="请填写视频地址" clearable></el-input>
-					</el-form-item>
-				</el-col>
-				<el-col :xs="24" :sm="24" :md="24" :lg="24" :xl="24">
-					<el-form-item label="公告内容" prop="content" :rules="[{ required: true, message: '请填写公告内容', trigger: 'blur' }]">
-						<editor v-model:get-html="state.ruleForm.content" placeholder="请填写公告内容" height="450px" />
 					</el-form-item>
 				</el-col>
+				<!--	安全卫士			-->
+				<template v-if="state.ruleForm.bulletinTypeId === 'aqws'">
+					<el-col>
+						<el-form-item label="志愿者类型" prop="safetyTypeId" :rules="[{ required: true, message: '请选择志愿者类型', trigger: 'change' }]">
+							<el-checkbox-group v-model="state.ruleForm.safetyTypeId">
+								<el-checkbox :label="item.dicDataName" :value="item.dicDataValue" v-for="item in safetyTypesOptions" :key="item.dicDataValue" />
+							</el-checkbox-group>
+						</el-form-item>
+					</el-col>
+					<el-col>
+						<el-form-item label="形式" prop="shape" :rules="[{ required: true, message: '请选择形式', trigger: 'change' }]">
+							<el-radio-group v-model="state.ruleForm.shape" @change="selectType">
+								<el-radio :value="0">消息</el-radio>
+								<el-radio :value="1">视频</el-radio>
+							</el-radio-group>
+						</el-form-item>
+					</el-col>
+				</template>
+				<template v-if="state.ruleForm.shape === 0">
+					<el-col>
+						<el-form-item label="视频地址" prop="videoPath" :rules="[{ required: false, message: '请填写视频地址', trigger: 'blur' }]">
+							<el-input v-model="state.ruleForm.videoPath" placeholder="请填写视频地址" clearable></el-input>
+						</el-form-item>
+					</el-col>
+					<el-col :xs="24" :sm="24" :md="24" :lg="24" :xl="24">
+						<el-form-item label="内容" prop="content" :rules="[{ required: true, message: '请填写内容', trigger: 'blur' }]">
+							<editor v-model:get-html="state.ruleForm.content" placeholder="请填写内容" height="450px" />
+						</el-form-item>
+					</el-col>
+				</template>
+				<template v-else>
+					<el-col>
+						<el-form-item label="视频封面" prop="videoCoverImgUrl" :rules="[{ required: true, message: '请上传视频封面', trigger: 'change' }]">
+							<el-upload
+								class="avatar-uploader"
+								:action="action"
+								:show-file-list="false"
+								:on-success="updateSuccessCareCell"
+								ref="uploadListRefCareCell"
+								name="fileData"
+								:on-error="onUploadError1"
+								accept="image/*"
+								:disabled="uploadingDisabled1"
+								:before-upload="beforeUpload1"
+							>
+								<img v-if="careCellImgUrl" :src="careCellImgUrl" class="avatar" alt="" />
+								<SvgIcon v-else class="avatar-uploader-icon" name="ele-Plus" size="28px" />
+								<template #tip v-if="uploadLoading1">
+									<div class="el-upload__tip"><el-text type="danger">上传中,请稍等...</el-text></div>
+								</template>
+							</el-upload>
+						</el-form-item>
+					</el-col>
+					<el-col>
+						<el-form-item label="视频上传" prop="videoPath" :rules="[{ required: true, message: '请上传视频', trigger: 'change' }]">
+							<el-upload
+								ref="uploadVideoRef"
+								class="upload-demo w100"
+								:action="action"
+								:limit="1"
+								name="fileData"
+								:on-error="onUploadError"
+								:on-exceed="handleExceed"
+								accept="video/mp4,video/mov"
+								:on-success="updateSuccessVideoPath"
+								v-model:file-list="fileList"
+								:disabled="uploadingDisabled"
+								:before-upload="beforeUpload"
+								:on-remove="handRemove"
+							>
+								<template #trigger>
+									<el-button type="primary" :loading="uploadLoading" :disabled="uploadingDisabled">
+										<SvgIcon name="ele-Upload" class="mr5" /> {{ uploadLoading ? '上传中,请稍等...' : '视频上传' }}
+									</el-button>
+								</template>
+								<template #tip>
+									<div class="el-upload__tip">视频上传:支持上传mp4、mov格式的视频</div>
+								</template>
+							</el-upload>
+						</el-form-item>
+					</el-col>
+				</template>
 			</el-row>
 		</el-form>
 		<template #footer>
@@ -120,9 +176,9 @@
 </template>
 
 <script setup lang="tsx" name="noticeDetail">
-import { reactive, ref, defineAsyncComponent } from 'vue';
+import { reactive, ref, defineAsyncComponent, computed } from 'vue';
 import { throttle } from '@/utils/tools';
-import { ElMessage, FormInstance } from 'element-plus';
+import { ElMessage, FormInstance, genFileId, UploadFile, UploadFiles, UploadProps, UploadRawFile, UploadUserFile } from 'element-plus';
 import { disabledDate } from '@/utils/constants';
 import { ElCheckbox } from 'element-plus';
 import { addSnapshotBulletin, editSnapshotBulletinBase } from '@/api/snapshot/info';
@@ -152,9 +208,9 @@ const state = reactive<any>({
 		content: null, // 内容
 		videoPath: null, // 视频地址
 		sourceMode: '1', // 来源方式 默认自建
-		isSnapshot: false, // 是否随手拍
-		safetyTypes: [], // 志愿者类型
-		type: '1', // 公告形式
+		safetyTypeId: [], // 志愿者类型
+		shape: 0, // 公告形式
+		videoCoverImgUrl: null, // 视频封面
 	},
 });
 let loading = ref<boolean>(false); // 加载状态
@@ -186,7 +242,109 @@ const changeOrg = () => {
 	if (currentNode) state.ruleForm.departmentName = currentNode[0].label;
 	else state.ruleForm.departmentName = null;
 };
+// 选择类型
+const selectType = () => {
+	if (state.ruleForm.shape === 0) {
+		state.ruleForm.videoPath = null;
+		careCellImgUrl.value = '';
+		state.ruleForm.videoCoverImgUrl = null;
+		fileList.value = [];
+	} else {
+		state.ruleForm.content = null;
+	}
+};
+// 上传地址
+const action = computed(() => {
+	return import.meta.env.VITE_API_UPLOAD_URL + '/file/upload?source=hotline';
+});
+// 上传视频封面
+const uploadLoading1 = ref(false);
+const uploadingDisabled1 = ref(false);
+const careCellImgUrl = ref('');
+const uploadListRefCareCell = ref<RefType>();
+const beforeUpload1 = () => {
+	uploadingDisabled1.value = true;
+	uploadLoading1.value = true; // 模拟上传过程
+};
+const updateSuccessCareCell = (response: any, uploadFile: UploadFile, uploadFiles: UploadFiles) => {
+	if (response.result.path) {
+		careCellImgUrl.value = import.meta.env.VITE_API_UPLOAD_URL + response.result.path;
+		// careCellImgUrl.value = URL.createObjectURL(uploadFile.raw!);
+		state.ruleForm.videoCoverImgUrl = response.result.path;
+	} else {
+		uploadListRefCareCell.value.handleRemove(uploadFile);
+		ElMessage.error('上传失败');
+	}
+	setTimeout(() => {
+		uploadLoading1.value = false; // 模拟上传过程
+		uploadingDisabled1.value = false;
+	}, 100);
+};
+// 上传视频
+const uploadVideoRef = ref<RefType>();
+const fileList = ref<UploadFiles>([
+	/*{
+		name: '12239_1739325758.mp4',
+		url: '/file/files_indefinitely?id=08dd8555-5673-4e45-80eb-12cdc7ac8125&expires=1745739172&clientid=hotline&signature=BF5AD8DBEF553CDA7750BBDF01A07C33689FAB83DB5163CADE787E327E366DD426861371167F86296E6DE9C696F65F3C92F3742DE762EE50',
+	},*/
+]);
+const uploadLoading = ref(false);
+const uploadingDisabled = ref(false);
+const beforeUpload = () => {
+	uploadingDisabled.value = true;
+	uploadLoading.value = true; // 模拟上传过程
+};
+const handleExceed = (files: any, uploadFiles: UploadUserFile[]) => {
+	ElMessage.warning(`当前限制最多上传1个文件,已经上传了${uploadFiles.length}个文件,本次选择了 ${files.length} 个文件。`);
+	setTimeout(() => {
+		uploadLoading.value = false; // 模拟上传过程
+	}, 100);
+};
 
+const updateSuccessVideoPath = (response: any, uploadFile: UploadFile, uploadFiles: UploadFiles) => {
+	if (response.result.path) {
+		state.ruleForm.videoPath = response.result.path;
+	} else {
+		uploadVideoRef.value.handleRemove(uploadFile);
+		ElMessage.error('上传失败');
+	}
+	console.log(fileList.value, state.ruleForm.videoPath, '111');
+	setTimeout(() => {
+		uploadLoading.value = false; // 模拟上传过程
+		uploadingDisabled.value = false;
+	}, 100);
+};
+// 删除文件
+const handRemove = (uploadFile: UploadFile, uploadFiles: UploadFiles) => {
+	fileList.value = uploadFiles;
+	state.ruleForm.videoPath = null;
+};
+// 上传失败
+const onUploadError = (error: Error) => {
+	try {
+		const errMessage = JSON.parse(error.message)?.message ?? '上传失败';
+		ElMessage.error(errMessage);
+	} catch (e) {
+		ElMessage.error('上传失败');
+	}
+	setTimeout(() => {
+		uploadLoading.value = false; // 模拟上传过程
+		uploadingDisabled.value = false;
+	}, 100);
+};
+// 上传失败
+const onUploadError1 = (error: Error) => {
+	try {
+		const errMessage = JSON.parse(error.message)?.message ?? '上传失败';
+		ElMessage.error(errMessage);
+	} catch (e) {
+		ElMessage.error('上传失败');
+	}
+	setTimeout(() => {
+		uploadLoading1.value = false; // 模拟上传过程
+		uploadingDisabled1.value = false;
+	}, 100);
+};
 // 保存
 const onSubmit = throttle(async (formEl: FormInstance | undefined) => {
 	if (!formEl) return;
@@ -215,6 +373,7 @@ const closeDialog = () => {
 const close = () => {
 	ruleFormRef.value?.clearValidate();
 	ruleFormRef.value?.resetFields();
+	state.ruleForm.bulletinTypeId = null;
 };
 // 暴露变量
 defineExpose({
@@ -222,3 +381,31 @@ defineExpose({
 	closeDialog,
 });
 </script>
+<style scoped lang="scss">
+.avatar-uploader .avatar {
+	width: 178px;
+	height: 178px;
+	display: block;
+}
+</style>
+<style>
+.avatar-uploader .el-upload {
+	border: 1px dashed var(--el-border-color);
+	border-radius: 6px;
+	cursor: pointer;
+	position: relative;
+	overflow: hidden;
+	transition: var(--el-transition-duration-fast);
+}
+
+.avatar-uploader .el-upload:hover {
+	border-color: var(--el-color-primary);
+}
+.avatar-uploader-icon {
+	font-size: 28px;
+	color: #8c939d;
+	width: 178px;
+	height: 178px;
+	text-align: center;
+}
+</style>

+ 17 - 2
src/views/snapshot/info/sspConfig/components/Config-detail.vue

@@ -26,8 +26,23 @@
 				<span class="mr5">结束时间:{{ formatDate(state.ruleForm.bulletinTime, 'YYYY-mm-dd HH:MM:SS') }}</span>
 				<span>来源单位:{{ state.ruleForm.sourceOrgName }}</span>
 			</p>
-			<el-divider />
-			<div v-html="state.ruleForm.content"></div>
+			<!--		安全卫士	-->
+			<template v-if="state.ruleForm.bulletinTypeId === 'aqws'">
+				<p style="text-align: center">
+					<span class="mr5">志愿者类型:{{ state.ruleForm?.safetyTypeNames?.join(',') }}</span>
+					<span>形式:{{ state.ruleForm.shape === 0 ? '消息' : '视频' }}</span>
+				</p>
+				<el-divider />
+				<div v-html="state.ruleForm.content" v-if="state.ruleForm.shape === 0"></div>
+				<div v-else>
+					<div>视频封面:{{ state.ruleForm?.videoCoverImgUrl }}</div>
+					<div>视频地址:{{ state.ruleForm?.videoPath }}</div>
+				</div>
+			</template>
+			<template v-else>
+				<el-divider />
+				<div v-html="state.ruleForm.content"></div>
+			</template>
 		</el-form>
 		<template #footer>
 			<span class="dialog-footer">

+ 205 - 23
src/views/snapshot/info/sspConfig/components/Config-edit.vue

@@ -80,26 +80,86 @@
 						<el-checkbox v-model="state.ruleForm.isWeChat">微信公开</el-checkbox>
 						<el-checkbox v-model="state.ruleForm.isTop">是否置顶</el-checkbox>
 						<el-checkbox v-model="state.ruleForm.isPopup">是否飘窗</el-checkbox>
-						<el-checkbox v-model="state.ruleForm.isSnapshot">是否随手拍</el-checkbox>
-					</el-form-item>
-				</el-col>
-				<el-col>
-					<el-form-item label="志愿者类型" prop="safetyTypes" :rules="[{ required: true, message: '请选择志愿者类型', trigger: 'change' }]">
-						<el-checkbox-group v-model="state.ruleForm.safetyTypes">
-							<el-checkbox :label="item.dicDataName" :value="item.dicDataValue" v-for="item in safetyTypesOptions" :key="item.dicDataValue" />
-						</el-checkbox-group>
-					</el-form-item>
-				</el-col>
-				<el-col>
-					<el-form-item label="视频地址" prop="videoPath" :rules="[{ required: false, message: '请填写视频地址', trigger: 'blur' }]">
-						<el-input v-model="state.ruleForm.videoPath" placeholder="请填写视频地址" clearable></el-input>
-					</el-form-item>
-				</el-col>
-				<el-col :xs="24" :sm="24" :md="24" :lg="24" :xl="24">
-					<el-form-item label="内容" prop="content" :rules="[{ required: true, message: '请填写内容', trigger: 'blur' }]">
-						<editor v-model:get-html="state.ruleForm.content" placeholder="请填写内容" height="450px" />
 					</el-form-item>
 				</el-col>
+				<!--	安全卫士			-->
+				<template v-if="state.ruleForm.bulletinTypeId === 'aqws'">
+					<el-col>
+						<el-form-item label="志愿者类型" prop="safetyTypeId" :rules="[{ required: true, message: '请选择志愿者类型', trigger: 'change' }]">
+							<el-checkbox-group v-model="state.ruleForm.safetyTypeId">
+								<el-checkbox :label="item.dicDataName" :value="item.dicDataValue" v-for="item in safetyTypesOptions" :key="item.dicDataValue" />
+							</el-checkbox-group>
+						</el-form-item>
+					</el-col>
+					<el-col>
+						<el-form-item label="形式" prop="shape" :rules="[{ required: true, message: '请选择形式', trigger: 'change' }]">
+							<el-radio-group v-model="state.ruleForm.shape" @change="selectType">
+								<el-radio :value="0">消息</el-radio>
+								<el-radio :value="1">视频</el-radio>
+							</el-radio-group>
+						</el-form-item>
+					</el-col>
+				</template>
+				<template v-if="state.ruleForm.shape === 0">
+					<el-col>
+						<el-form-item label="视频地址" prop="videoPath" :rules="[{ required: false, message: '请填写视频地址', trigger: 'blur' }]">
+							<el-input v-model="state.ruleForm.videoPath" placeholder="请填写视频地址" clearable></el-input>
+						</el-form-item>
+					</el-col>
+					<el-col :xs="24" :sm="24" :md="24" :lg="24" :xl="24">
+						<el-form-item label="内容" prop="content" :rules="[{ required: true, message: '请填写内容', trigger: 'blur' }]">
+							<editor v-model:get-html="state.ruleForm.content" placeholder="请填写内容" height="450px" />
+						</el-form-item>
+					</el-col>
+				</template>
+				<template v-else>
+					<el-col>
+						<el-form-item label="视频封面" prop="videoCoverImgUrl" :rules="[{ required: true, message: '请上传视频封面', trigger: 'change' }]">
+							<el-upload
+								class="avatar-uploader"
+								:action="action"
+								:show-file-list="false"
+								:on-success="updateSuccessCareCell"
+								ref="uploadListRefCareCell"
+								name="fileData"
+								:on-error="onUploadError"
+								accept="image/*"
+								:disabled="uploadingDisabled"
+							>
+								<img v-if="careCellImgUrl" :src="careCellImgUrl" class="avatar" alt="" />
+								<SvgIcon v-else class="avatar-uploader-icon" name="ele-Plus" size="28px" />
+							</el-upload>
+						</el-form-item>
+					</el-col>
+					<el-col>
+						<el-form-item label="视频上传" prop="videoPath" :rules="[{ required: true, message: '请上传视频', trigger: 'change' }]">
+							<el-upload
+								ref="uploadVideoRef"
+								class="upload-demo w100"
+								:action="action"
+								:limit="1"
+								name="fileData"
+								:on-error="onUploadError"
+								:on-exceed="handleExceed"
+								accept="video/mp4,video/mov"
+								:on-success="updateSuccessVideoPath"
+								v-model:file-list="fileList"
+								:disabled="uploadingDisabled"
+								:before-upload="beforeUpload"
+								:on-remove="handRemove"
+							>
+								<template #trigger>
+									<el-button type="primary" :loading="uploadLoading" :disabled="uploadingDisabled">
+										<SvgIcon name="ele-Upload" class="mr5" /> {{ uploadLoading ? '上传中,请稍等...' : '视频上传' }}
+									</el-button>
+								</template>
+								<template #tip>
+									<div class="el-upload__tip">视频上传:支持上传mp4、mov格式的视频</div>
+								</template>
+							</el-upload>
+						</el-form-item>
+					</el-col>
+				</template>
 			</el-row>
 		</el-form>
 		<template #footer>
@@ -112,9 +172,9 @@
 </template>
 
 <script setup lang="tsx" name="noticeDetail">
-import { reactive, ref, defineAsyncComponent } from 'vue';
+import { reactive, ref, defineAsyncComponent, computed } from 'vue';
 import { throttle } from '@/utils/tools';
-import { ElMessage, FormInstance } from 'element-plus';
+import { ElMessage, FormInstance, UploadFile, UploadFiles } from 'element-plus';
 import { disabledDate } from '@/utils/constants';
 import { ElCheckbox } from 'element-plus';
 import { editSnapshotBulletin, editSnapshotBulletinBase, getSnapshotBulletinDetail } from '@/api/snapshot/info';
@@ -144,8 +204,9 @@ const state = reactive<any>({
 		content: null, // 内容
 		videoPath: null, // 视频地址
 		sourceMode: '1', // 来源方式 默认自建
-		isSnapshot: false, // 是否随手拍
-		safetyTypes: [], // 志愿者类型
+		safetyTypeId: [], // 志愿者类型
+		shape: 0, // 公告形式
+		videoCoverImgUrl: null, // 视频封面
 	},
 });
 let loading = ref<boolean>(false); // 加载状态
@@ -170,6 +231,16 @@ const openDialog = async (id: string) => {
 			dicDataValue: result.result?.bulletinTypeId,
 			dicDataName: result.result?.bulletinTypeName,
 		};
+		if (result.result?.videoCoverImgUrl) careCellImgUrl.value = import.meta.env.VITE_API_UPLOAD_URL + result.result?.videoCoverImgUrl; // 视频封面
+		if (result.result?.videoPath) {
+			//视频地址
+			fileList.value = [
+				{
+					name: '视频',
+					url: import.meta.env.VITE_API_UPLOAD_URL + result.result?.videoPath,
+				},
+			];
+		}
 		loading.value = false;
 	} catch (error) {
 		console.log(error);
@@ -182,7 +253,89 @@ const changeOrg = () => {
 	if (currentNode) state.ruleForm.departmentName = currentNode[0].label;
 	else state.ruleForm.departmentName = null;
 };
-
+// 选择类型
+const selectType = () => {
+	if (state.ruleForm.shape === 0) {
+		state.ruleForm.videoPath = null;
+		careCellImgUrl.value = '';
+		state.ruleForm.videoCoverImgUrl = null;
+		fileList.value = [];
+	} else {
+		state.ruleForm.content = null;
+	}
+};
+// 上传地址
+const action = computed(() => {
+	return import.meta.env.VITE_API_UPLOAD_URL + '/file/upload?source=hotline';
+});
+// 上传视频封面
+const careCellImgUrl = ref('');
+const uploadListRefCareCell = ref<RefType>();
+const updateSuccessCareCell = (response: any, uploadFile: UploadFile, uploadFiles: UploadFiles) => {
+	if (response.result.path) {
+		careCellImgUrl.value = import.meta.env.VITE_API_UPLOAD_URL + response.result.path;
+		// careCellImgUrl.value = URL.createObjectURL(uploadFile.raw!);
+		state.ruleForm.videoCoverImgUrl = response.result.path;
+	} else {
+		uploadListRefCareCell.value.handleRemove(uploadFile);
+		ElMessage.error('上传失败');
+	}
+	setTimeout(() => {
+		uploadLoading.value = false; // 模拟上传过程
+		uploadingDisabled.value = false;
+	}, 100);
+};
+// 上传视频
+const uploadVideoRef = ref<RefType>();
+const fileList = ref<UploadFiles>([
+	/*{
+		name: '12239_1739325758.mp4',
+		url: '/file/files_indefinitely?id=08dd8555-5673-4e45-80eb-12cdc7ac8125&expires=1745739172&clientid=hotline&signature=BF5AD8DBEF553CDA7750BBDF01A07C33689FAB83DB5163CADE787E327E366DD426861371167F86296E6DE9C696F65F3C92F3742DE762EE50',
+	},*/
+]);
+const uploadLoading = ref(false);
+const beforeUpload = () => {
+	uploadingDisabled.value = true;
+	uploadLoading.value = true; // 模拟上传过程
+};
+const handleExceed = (files: any, uploadFiles: UploadUserFile[]) => {
+	ElMessage.warning(`当前限制最多上传1个文件,已经上传了${uploadFiles.length}个文件,本次选择了 ${files.length} 个文件。`);
+	setTimeout(() => {
+		uploadLoading.value = false; // 模拟上传过程
+	}, 100);
+};
+const uploadingDisabled = ref(false);
+const updateSuccessVideoPath = (response: any, uploadFile: UploadFile, uploadFiles: UploadFiles) => {
+	if (response.result.path) {
+		state.ruleForm.videoPath = response.result.path;
+	} else {
+		uploadVideoRef.value.handleRemove(uploadFile);
+		ElMessage.error('上传失败');
+	}
+	console.log(fileList.value, state.ruleForm.videoPath, '111');
+	setTimeout(() => {
+		uploadLoading.value = false; // 模拟上传过程
+		uploadingDisabled.value = false;
+	}, 100);
+};
+// 删除文件
+const handRemove = (uploadFile: UploadFile, uploadFiles: UploadFiles) => {
+	fileList.value = uploadFiles;
+	state.ruleForm.videoPath = null;
+};
+// 上传失败
+const onUploadError = (error: Error) => {
+	try {
+		const errMessage = JSON.parse(error.message)?.message ?? '上传失败';
+		ElMessage.error(errMessage);
+	} catch (e) {
+		ElMessage.error('上传失败');
+	}
+	setTimeout(() => {
+		uploadLoading.value = false; // 模拟上传过程
+		uploadingDisabled.value = false;
+	}, 100);
+};
 // 保存
 const onSubmit = throttle(async (formEl: FormInstance | undefined) => {
 	if (!formEl) return;
@@ -211,6 +364,7 @@ const closeDialog = () => {
 const close = () => {
 	ruleFormRef.value?.clearValidate();
 	ruleFormRef.value?.resetFields();
+	state.ruleForm.bulletinTypeId = null;
 };
 // 暴露变量
 defineExpose({
@@ -218,3 +372,31 @@ defineExpose({
 	closeDialog,
 });
 </script>
+<style scoped lang="scss">
+.avatar-uploader .avatar {
+	width: 178px;
+	height: 178px;
+	display: block;
+}
+</style>
+<style>
+.avatar-uploader .el-upload {
+	border: 1px dashed var(--el-border-color);
+	border-radius: 6px;
+	cursor: pointer;
+	position: relative;
+	overflow: hidden;
+	transition: var(--el-transition-duration-fast);
+}
+
+.avatar-uploader .el-upload:hover {
+	border-color: var(--el-color-primary);
+}
+.avatar-uploader-icon {
+	font-size: 28px;
+	color: #8c939d;
+	width: 178px;
+	height: 178px;
+	text-align: center;
+}
+</style>

+ 1 - 1
src/views/snapshot/info/sspConfig/index.vue

@@ -198,7 +198,7 @@ const gridOptions = reactive<any>({
 		{
 			field: 'snapshotBulletinTypeName',
 			title: '类别名称',
-			width: 180,
+			width: 200,
 		},
 		{
 			field: 'title',

+ 16 - 15
src/views/snapshot/reAudit/components/Re-audit.vue

@@ -98,6 +98,18 @@
 					<!-- 不同意 -->
 					<template v-if="state.ruleForm.pointsStatus === 1">
 						<el-col :xs="24" :sm="12" :md="12" :lg="12" :xl="12">
+							<el-form-item
+								label="额外扣除积分类型"
+								prop="extraDeductionPointsTypeId"
+								label-width="140px"
+								:rules="[{ required: false, message: '请选择额外扣除积分类型', trigger: 'change' }]"
+							>
+								<el-select v-model="state.ruleForm.extraDeductionPointsTypeId" clearable placeholder="请选择额外扣除积分类型" @change="selectType">
+									<el-option v-for="item in extraDeductionPointsType" :label="item.dicDataName" :key="item.dicDataValue" :value="item.dicDataValue" />
+								</el-select>
+							</el-form-item>
+						</el-col>
+						<el-col :xs="24" :sm="12" :md="12" :lg="12" :xl="12" v-if="state.ruleForm.extraDeductionPointsTypeId">
 							<el-form-item
 								label="额外扣除积分"
 								prop="extraDeductedPoints"
@@ -113,18 +125,6 @@
 								/>
 							</el-form-item>
 						</el-col>
-						<el-col :xs="24" :sm="12" :md="12" :lg="12" :xl="12">
-							<el-form-item
-								label="额外扣除积分类型"
-								prop="extraDeductionPointsTypeId"
-								label-width="140px"
-								:rules="[{ required: false, message: '请选择额外扣除积分类型', trigger: 'change' }]"
-							>
-								<el-select v-model="state.ruleForm.extraDeductionPointsTypeId" clearable placeholder="请选择额外扣除积分类型" @change="selectType">
-									<el-option v-for="item in extraDeductionPointsType" :label="item.dicDataName" :key="item.dicDataValue" :value="item.dicDataValue" />
-								</el-select>
-							</el-form-item>
-						</el-col>
 					</template>
 				</el-row>
 			</template>
@@ -210,10 +210,11 @@ const openDialog = async (row: any, type?: string) => {
 			state.ruleForm.extraDeductedPoints = result.extraDeductedPoints;
 			// 默认同意
 			state.ruleForm.status = 0;
-			selectStatus(0)
-			if(state.infoForm.isPoints){ // 积分审批默认同意
+			selectStatus(0);
+			if (state.infoForm.isPoints) {
+				// 积分审批默认同意
 				state.ruleForm.pointsStatus = 0;
-				selectPointStatus(0)
+				selectPointStatus(0);
 			}
 			loading.value = false;
 		}

+ 76 - 72
src/views/todo/seats/accept/lzAccept.vue

@@ -440,6 +440,7 @@ import { removeDuplicate } from '@/utils/arrayOperation';
 import { Session } from '@/utils/storage';
 import { watchPausable } from '@vueuse/core';
 import { useThemeConfig } from '@/stores/themeConfig';
+import other from '@/utils/other';
 
 // 引入组件
 const Knowledge = defineAsyncComponent(() => import('@/views/todo/seats/accept/Knowledge.vue')); // 知识库
@@ -458,73 +459,79 @@ const LZProcess = defineAsyncComponent(() => import('@/components/ProcessAudit/L
 // 定义变量内容
 const storesThemeConfig = useThemeConfig();
 const { themeConfig } = storeToRefs(storesThemeConfig);
+const storesUserInfo = useUserInfo(); // 用户信息
+const { userInfos } = storeToRefs(storesUserInfo); // 用户信息
+const appConfigStore = useAppConfig();
+const { AppConfigInfo } = storeToRefs(appConfigStore); // 系统配置信息
 
+// 默认表单内容
+const defaultRuleForm: EmptyObjectType = {
+	sourceChannel: null, // 来源频道
+	sourceChannelCode: null, //来源频道code
+	transferPhone: null, // 转接来源
+	fromPhone: null, // 来电号码
+	acceptorName: userInfos.value.name, // 员工姓名
+	acceptorStaffNo: userInfos.value.staffNo, // 员工工号
+	fromName: null, // 来电人姓名
+	fromGender: 1, // 来电人性别 默认先生
+	identityType: 1, // 来电/信人身份 默认市民
+	licenceType: null, // 证件类型
+	licenceTypeCode: null, // 证件类型code
+	licenceNo: null, // 证件号码
+	ageRange: null, // 年龄段
+	ageRangeCode: null, // 年龄段code
+	contact: null, // 联系电话
+	isSecret: false, // 是否保密 默认false
+	acceptSms: false, // 是否接收短信 默认false
+	no: null, // 工单编码
+	title: null, // 工单标题
+	hotspotId: null, // 热点分类
+	hotspotSpliceName: null, // 热点分类拼接名称
+	hotspotName: null, // 热点分类名称
+	hotspotCode: null, // 热点分类code
+	hotspotExternal: [], // 热点分类外部数据
+	eventCategoryId: null, // 事件分类
+	incidentTime: null, // 事发时间
+	incidentPurpose: null, // 事件目的
+	/*		areaCode: themeConfig.value.cityCode, // 区域编码
+	city: themeConfig.value.cityName, // 市*/
+	areaCode: null, // 区域编码
+	city: null, // 市
+	street: null, // 街道
+	isRepeat: 'false', // 是否重复工单 默认否
+	pushType: null, // 推送类型
+	pushTypeCode: null, // 推送类型code
+	content: '', // 工单内容
+	duplicateIds: [], //重复工单id
+	duplicateTitle: null, // 重复工单标题
+	callAddress: null, // 来电归属地
+	repeatableEventDetails: [], //重复性事件
+	orderExtension: null, // 拓展信息
+	transpond: false, // 是否市州互转
+	isEnforcementOrder: false, // 是否行政执法工单
+	focusOnEventsArr: [], // 重点关注事项
+	focusOnEvents: null, // 重点关注事项 字符串
+	isFormalistWorkOrder: false, // 是否形式主义工单
+	isSensitiveWorkOrders: false, // 是否敏感类工单
+	isUrgent: false, // 是否紧急工单
+	isThreePartyConference: false, // 是否三方同v话
+	is24HoursComplete: false, // 24小时紧急工单
+	company: null, // 工作单位
+	orderPushTypes: [], // 推送分类多选
+	acceptType: '咨询', // 受理类型
+	acceptTypeCode: '10', // 受理类型code
+	acceptTypeObj: {
+		// 默认咨询
+		dicDataValue: '10',
+		dicDataName: '咨询',
+	},
+	tags: [], // 工单标签
+	longitude: AppConfigInfo.value?.locationCenter[0], //经度
+	latitude: AppConfigInfo.value?.locationCenter[1], //纬度
+};
 const state = reactive<any>({
 	createBy: 'manual', // 工单创建方式 默认手动创建  tel:来电弹单  letter:互联网来信 默认表示手动创建
-	ruleForm: {
-		sourceChannel: null, // 来源频道
-		sourceChannelCode: null, //来源频道code
-		transferPhone: null, // 转接来源
-		fromPhone: null, // 来电号码
-		acceptorName: null, // 员工姓名
-		acceptorStaffNo: null, // 员工工号
-		fromName: null, // 来电人姓名
-		fromGender: 1, // 来电人性别 默认先生
-		identityType: 1, // 来电/信人身份 默认市民
-		licenceType: null, // 证件类型
-		licenceTypeCode: null, // 证件类型code
-		licenceNo: null, // 证件号码
-		ageRange: null, // 年龄段
-		ageRangeCode: null, // 年龄段code
-		contact: null, // 联系电话
-		isSecret: false, // 是否保密 默认false
-		acceptSms: false, // 是否接收短信 默认false
-		no: null, // 工单编码
-		title: null, // 工单标题
-		hotspotId: null, // 热点分类
-		hotspotSpliceName: null, // 热点分类拼接名称
-		hotspotName: null, // 热点分类名称
-		hotspotCode: null, // 热点分类code
-		hotspotExternal: [], // 热点分类外部数据
-		eventCategoryId: null, // 事件分类
-		incidentTime: null, // 事发时间
-		incidentPurpose: null, // 事件目的
-		/*		areaCode: themeConfig.value.cityCode, // 区域编码
-		city: themeConfig.value.cityName, // 市*/
-		areaCode: null, // 区域编码
-		city: null, // 市
-		street: null, // 街道
-		isRepeat: 'false', // 是否重复工单 默认否
-		pushType: null, // 推送类型
-		pushTypeCode: null, // 推送类型code
-		content: '', // 工单内容
-		duplicateIds: [], //重复工单id
-		duplicateTitle: null, // 重复工单标题
-		callAddress: null, // 来电归属地
-		repeatableEventDetails: [], //重复性事件
-		orderExtension: null, // 拓展信息
-		transpond: false, // 是否市州互转
-		isEnforcementOrder: false, // 是否行政执法工单
-		focusOnEventsArr: [], // 重点关注事项
-		focusOnEvents: null, // 重点关注事项 字符串
-		isFormalistWorkOrder: false, // 是否形式主义工单
-		isSensitiveWorkOrders: false, // 是否敏感类工单
-		isUrgent: false, // 是否紧急工单
-		isThreePartyConference: false, // 是否三方同v话
-		is24HoursComplete: false, // 24小时紧急工单
-		company: null, // 工作单位
-		orderPushTypes: [], // 推送分类多选
-		acceptType: '咨询', // 受理类型
-		acceptTypeCode: '10', // 受理类型code
-		acceptTypeObj: {
-			// 默认咨询
-			dicDataValue: '10',
-			dicDataName: '咨询',
-		},
-		tags: [], // 工单标签
-		longitude: null, //经度
-		latitude: null, //纬度
-	},
+	ruleForm: defaultRuleForm,
 	formLoading: false, // 表单加载状态
 	hotspotExternal: [], // 热点分类外部数据
 	eventCategoryExternal: [], // 事件分类外部数据
@@ -553,14 +560,6 @@ const state = reactive<any>({
 	orderId: null, // 工单id
 	tagsViewList: [],
 });
-const storesUserInfo = useUserInfo(); // 用户信息
-const { userInfos } = storeToRefs(storesUserInfo); // 用户信息
-const appConfigStore = useAppConfig();
-const { AppConfigInfo } = storeToRefs(appConfigStore); // 系统配置信息
-state.ruleForm.acceptorName = userInfos.value.name; // 员工姓名
-state.ruleForm.acceptorStaffNo = userInfos.value.staffNo; // 员工工号
-state.ruleForm.longitude = AppConfigInfo.value.locationCenter[0]; // 默认经度
-state.ruleForm.latitude = AppConfigInfo.value.locationCenter[1]; // 默认纬度
 const route = useRoute(); // 路由
 // 选择来源渠道
 const changeChannel = (val: any) => {
@@ -1130,8 +1129,13 @@ const loadBaseData = async () => {
 		console.log(error);
 	}
 };
+// 重置表单
+const resetForm = () => {
+	state.ruleForm = other.deepClone(defaultRuleForm);
+};
 // 电话进来的来信
 const loadCreatedBy = () => {
+	resetForm();
 	if (route.query.createBy) {
 		//  route.query.createBy  createBy 代表来源  tel:来电弹单  letter:互联网来信 默认表示手动创建
 		state.createBy = route.query.createBy;