소스 검색

feat:新增外呼市民甘丽 外呼模板配置 智能外呼任务 短信任务 二次办理统计 二次办理满意度 页面;

zhangchong 11 달 전
부모
커밋
9c2b319724

+ 2 - 7
src/views/auxiliary/citizen/index.vue

@@ -21,11 +21,6 @@
 			</el-form>
 		</el-card>
 		<el-card shadow="never">
-			<!--      <div class="mb20">
-        <el-button type="primary" @click="onLexiconDelete" v-waves v-auth="'auxiliary:citizen:delete'" :disabled="!multipleSelection.length">
-          <SvgIcon name="ele-Delete" class="mr5" />删除
-        </el-button>
-      </div>-->
 			<!-- 表格 -->
 			<ProTable
 				ref="proTableRef"
@@ -53,9 +48,9 @@
 
 <script lang="tsx" setup name="auxiliaryCitizen">
 import { defineAsyncComponent, onMounted, reactive, ref } from 'vue';
-import { ElButton, ElMessage, ElMessageBox, FormInstance } from 'element-plus';
+import { ElButton, FormInstance } from 'element-plus';
 import { formatDate } from '@/utils/formatTime';
-import { citizenDelete, citizenList } from '@/api/auxiliary/citizen';
+import { citizenList } from '@/api/auxiliary/citizen';
 
 // 引入组件
 const TagsRecord = defineAsyncComponent(() => import('@/views/auxiliary/citizen/components/Tags-record.vue')); // 标签记录

+ 19 - 47
src/views/auxiliary/externalCitizen/index.vue

@@ -2,17 +2,17 @@
   <div class="auxiliary-external-citizen-container layout-pd">
     <el-card shadow="never">
       <el-form :model="state.queryParams" ref="ruleFormRef" inline @submit.native.prevent>
-        <el-form-item label="市民联系方式" prop="PhoneNumber">
+        <el-form-item label="市民姓名" prop="PhoneNumber">
           <el-input
             v-model="state.queryParams.PhoneNumber"
-            placeholder="请输入市民联系方式"
+            placeholder="请输入市民姓名"
             clearable
             @keyup.enter="handleQuery"
             class="keyword-input"
           />
         </el-form-item>
-        <el-form-item label="市民标签" prop="Label">
-          <el-input v-model="state.queryParams.Label" placeholder="请输入市民标签" clearable @keyup.enter="handleQuery" class="keyword-input" />
+        <el-form-item label="联系电话" prop="Label">
+          <el-input v-model="state.queryParams.Label" placeholder="请输入市民联系电话" clearable @keyup.enter="handleQuery" class="keyword-input" />
         </el-form-item>
         <el-form-item>
           <el-button type="primary" @click="handleQuery" :loading="state.loading"> <SvgIcon name="ele-Search" class="mr5" />查询 </el-button>
@@ -21,11 +21,6 @@
       </el-form>
     </el-card>
     <el-card shadow="never">
-      <!--      <div class="mb20">
-        <el-button type="primary" @click="onLexiconDelete" v-waves v-auth="'auxiliary:citizen:delete'" :disabled="!multipleSelection.length">
-          <SvgIcon name="ele-Delete" class="mr5" />删除
-        </el-button>
-      </div>-->
       <!-- 表格 -->
       <ProTable
         ref="proTableRef"
@@ -37,10 +32,9 @@
         v-model:page-index="state.queryParams.PageIndex"
         v-model:page-size="state.queryParams.PageSize"
       >
-        <!-- 表格操作 -->
-        <template #operation="{ row }">
-          <el-button link type="primary" @click="onTagsRecord(row)" v-auth="'auxiliary:citizen:tag'" title="查看市民标签记录"> 标签记录 </el-button>
-          <el-button link type="primary" @click="onTagsEdit(row)" v-auth="'auxiliary:citizen:edit'" title="编辑市民画像"> 编辑 </el-button>
+        <template #tableHeader="scope">
+          <el-button type="primary" @click="onImport" v-auth="'auxiliary:externalCitizen:import'"> <SvgIcon name="ele-Upload" class="mr5" /> 导入 </el-button>
+          <el-button type="primary" @click="onDownload" v-auth="'auxiliary:externalCitizen:download'"> <SvgIcon name="ele-Download" class="mr5" /> 模板下载 </el-button>
         </template>
       </ProTable>
     </el-card>
@@ -54,7 +48,6 @@
 <script lang="tsx" setup name="auxiliaryExternalCitizen">
 import { defineAsyncComponent, onMounted, reactive, ref } from 'vue';
 import { ElButton, ElMessage, ElMessageBox, FormInstance } from 'element-plus';
-import { formatDate } from '@/utils/formatTime';
 import { citizenDelete, citizenList } from '@/api/auxiliary/citizen';
 
 // 引入组件
@@ -64,27 +57,8 @@ const TagsEdit = defineAsyncComponent(() => import('@/views/auxiliary/citizen/co
 const proTableRef = ref<RefType>(); // 表格ref
 // 表格配置项
 const columns = ref<any[]>([
-  { prop: 'phoneNumber', label: '市民联系方式', width: 200 },
-  { prop: 'label', label: '市民标签', width: 300 },
-  { prop: 'creatorName', label: '创建人' },
-  {
-    prop: 'creationTime',
-    label: '创建时间',
-    width: 170,
-    render: (scope) => {
-      return <span>{formatDate(scope.row.creationTime, 'YYYY-mm-dd HH:MM:SS')}</span>;
-    },
-  },
-  { prop: 'lastModificationName', label: '更新人' },
-  {
-    prop: 'lastModificationTime',
-    label: '更新时间',
-    width: 170,
-    render: (scope) => {
-      return <span>{formatDate(scope.row.lastModificationTime, 'YYYY-mm-dd HH:MM:SS')}</span>;
-    },
-  },
-  { prop: 'operation', label: '操作', fixed: 'right', width: 140, align: 'center' },
+  { prop: 'name', label: '市民姓名' },
+  { prop: 'phoneNumber', label: '联系电话' },
 ]);
 // 定义变量内容
 const state = reactive({
@@ -107,7 +81,7 @@ const handleQuery = () => {
 };
 // 获取列表
 const queryList = () => {
-  state.loading = true;
+  /*state.loading = true;
   citizenList(state.queryParams)
     .then((res) => {
       state.loading = false;
@@ -116,7 +90,7 @@ const queryList = () => {
     })
     .finally(() => {
       state.loading = false;
-    });
+    });*/
 };
 // 重置表单
 const resetQuery = (formEl: FormInstance | undefined) => {
@@ -124,16 +98,14 @@ const resetQuery = (formEl: FormInstance | undefined) => {
   formEl.resetFields();
   queryList();
 };
-// 标签记录
-const tagsRecordRef = ref<RefType>();
-const onTagsRecord = (row: any) => {
-  tagsRecordRef.value.openDialog(row);
-};
-// 编辑标签
-const TagsEditRef = ref<RefType>();
-const onTagsEdit = (row: any) => {
-  TagsEditRef.value.openDialog(row);
-};
+// 导入
+const onImport = ()=>{
+
+}
+// 模板下载
+const onDownload = ()=>{
+
+}
 // 页面加载时
 onMounted(() => {
   queryList();

+ 1 - 1
src/views/auxiliary/orderLexicon/components/Order-lexicon-add.vue

@@ -1,5 +1,5 @@
 <template>
-	<el-dialog v-model="state.dialogVisible" width="800px" draggable title="新增工单词库" @close="close">
+	<el-dialog v-model="state.dialogVisible" width="800px" draggable title="新增工单词库" @close="close"  append-to-body destroy-on-close>
 		<el-form :model="state.ruleForm" label-width="100px" ref="ruleFormRef">
 			<el-row :gutter="10">
 				<el-col :xs="24" :sm="12" :md="12" :lg="12" :xl="12">

+ 1 - 1
src/views/auxiliary/orderLexicon/components/Order-lexicon-edit.vue

@@ -1,5 +1,5 @@
 <template>
-	<el-dialog v-model="state.dialogVisible" width="800px" draggable title="编辑工单词库" @close="close">
+	<el-dialog v-model="state.dialogVisible" width="800px" draggable title="编辑工单词库" @close="close"  append-to-body destroy-on-close>
 		<el-form :model="state.ruleForm" label-width="100px" ref="ruleFormRef">
 			<el-row :gutter="10">
 				<el-col :xs="24" :sm="12" :md="12" :lg="12" :xl="12">

+ 237 - 0
src/views/auxiliary/smartCallOut/components/Create-task.vue

@@ -0,0 +1,237 @@
+<template>
+	<el-dialog v-model="state.dialogVisible" width="60%" draggable title="创建任务" @close="close" append-to-body destroy-on-close>
+		<el-form :model="state.ruleForm" label-width="120px" ref="ruleFormRef">
+			<el-row :gutter="10">
+				<el-col :xs="24" :sm="12" :md="12" :lg="12" :xl="12">
+					<el-form-item label="任务名称" prop="tag" :rules="[{ required: true, message: '请输入任务名称', trigger: 'blur' }]">
+						<el-input v-model="state.ruleForm.tag" placeholder="请输入任务名称" clearable></el-input>
+					</el-form-item>
+				</el-col>
+				<el-col :xs="24" :sm="12" :md="12" :lg="12" :xl="12">
+					<el-form-item label="外呼时间段" prop="time" :rules="[{ required: true, message: '请选择外呼时间段', trigger: 'change' }]">
+            <el-date-picker
+              v-model="state.ruleForm.time"
+              type="datetimerange"
+              unlink-panels
+              range-separator="至"
+              start-placeholder="开始时间"
+              end-placeholder="结束时间"
+              :shortcuts="shortcuts"
+              value-format="YYYY-MM-DD[T]HH:mm:ss"
+            />
+					</el-form-item>
+				</el-col>
+				<el-col :xs="24" :sm="12" :md="12" :lg="12" :xl="12">
+					<el-form-item label="节日禁呼" prop="festivalBan" :rules="[{ required: true, message: '请选择节日禁呼', trigger: 'change' }]">
+						<el-radio-group v-model="state.ruleForm.festivalBan">
+							<el-radio :label="1">是</el-radio>
+							<el-radio :label="0">否</el-radio>
+						</el-radio-group>
+					</el-form-item>
+				</el-col>
+				<el-col :xs="24" :sm="12" :md="12" :lg="12" :xl="12">
+					<el-form-item label="外呼模板" prop="PushBusiness" :rules="[{ required: true, message: '请选择外呼模板', trigger: 'change' }]">
+						<el-select-v2
+							v-model="state.ruleForm.PushBusiness"
+							filterable
+							:options="ePushBusinessData"
+							:props="{
+								label: 'name',
+								value: 'id',
+							}"
+							placeholder="请选择外呼模板"
+							class="w100"
+						/>
+					</el-form-item>
+				</el-col>
+			</el-row>
+			<el-divider />
+			<ProTable
+				ref="proTableRef"
+				:columns="columns"
+				:data="state.tableData"
+				:loading="state.loading"
+				:pagination="false"
+				:tool-button="false"
+				max-height="400px"
+				row-key="id"
+			>
+				<template #tableHeader="scope">
+					<el-button type="primary" @click="addCitizen"> <SvgIcon name="ele-Plus" class="mr5" />添加市民 </el-button>
+					<el-button type="primary" @click="importCitizen"> <SvgIcon name="ele-Upload" class="mr5" />导入市民 </el-button>
+					<el-button type="primary" @click="temDownload"> <SvgIcon name="ele-Download" class="mr5" />模板下载 </el-button>
+					<el-button type="primary" @click="onDelete" :disabled="!scope.isSelected"> <SvgIcon name="ele-Delete" class="mr5" />批量删除 </el-button>
+					<el-button type="primary" @click="onClear"> <SvgIcon name="ele-CircleClose" class="mr5" /> 清空 </el-button>
+				</template>
+				<!-- 表格操作 -->
+				<template #operation="{ row }">
+					<el-button link type="primary" @click="onDel(row)" title="删除"> 删除 </el-button>
+				</template>
+			</ProTable>
+		</el-form>
+		<template #footer>
+			<span class="dialog-footer">
+				<el-button @click="closeDialog" class="default-button">取 消</el-button>
+				<el-button type="primary" @click="onSubmit(ruleFormRef)" :loading="loading" :disabled="!canChoose">确 定</el-button>
+			</span>
+		</template>
+	</el-dialog>
+	<citizen-add ref="addCitizenRef" @selectCitizen="selectCitizen" />
+</template>
+
+<script setup lang="ts">
+import { computed, defineAsyncComponent, nextTick, reactive, ref } from 'vue';
+import { ElButton, ElInput, ElMessage, ElMessageBox, FormInstance } from 'element-plus';
+import { throttle } from '@/utils/tools';
+import { orderLexiconAdd } from '@/api/auxiliary/orderLexicon';
+import { removeDuplicate } from '@/utils/arrayOperation';
+import { shortcuts } from "@/utils/constants";
+
+const CitizenAdd = defineAsyncComponent(() => import('@/views/auxiliary/smsTask/components/Add-citizen.vue')); // 创建任务
+
+// 定义子组件向父组件传值/事件
+const emit = defineEmits(['updateList']);
+// 定义变量内容
+const state = reactive<any>({
+	dialogVisible: false,
+	ruleForm: {
+		tag: '', // 工单关键词
+		classifyArray: [], // 标签分类
+		isEnable: 1, // 是否启用
+		synonym: '', // 违禁同义词
+		remark: '', // 备注说明
+	},
+	tableData: [], // 表格内容
+});
+let loading = ref<boolean>(false); // 加载状态
+// 打开弹窗
+const ruleFormRef = ref<RefType>();
+const ePushBusinessData = ref([]);
+const openDialog = async () => {
+	ruleFormRef.value?.resetFields();
+	try {
+		state.dialogVisible = true;
+	} catch (error) {
+		console.log(error);
+	}
+};
+// 关闭弹窗
+const closeDialog = () => {
+	state.dialogVisible = false;
+};
+const close = () => {
+	ruleFormRef.value?.resetFields();
+	ruleFormRef.value?.resetFields();
+};
+// 表格配置项
+const proTableRef = ref<RefType>(); // 表格ref
+const canChoose = computed(() => {
+	return proTableRef.value?.selectedList.length;
+});
+const columns = ref<any[]>([
+	{ type: 'selection', fixed: 'left', width: 55, align: 'center' },
+	{ prop: 'name', label: '市民姓名' },
+	{ prop: 'phoneNumber', label: '联系电话' },
+	{ prop: 'operation', label: '操作', fixed: 'right', width: 80, align: 'center' },
+]);
+// 添加市民
+const addCitizenRef = ref<RefType>();
+const addCitizen = () => {
+	addCitizenRef.value.openDialog();
+};
+// 导入市民
+const importCitizen = () => {};
+// 模板下载
+const temDownload = () => {};
+// 单个删除
+const onDel = (row: any) => {
+	ElMessageBox.confirm('确定要删除?', '提示', {
+		confirmButtonText: '确定',
+		cancelButtonText: '取消',
+		type: 'warning',
+		draggable: true,
+		autofocus: false,
+	})
+		.then(() => {
+			if (row.id) {
+				state.tableData = state.tableData.filter((item: any) => item.id !== row.id);
+			} else {
+				state.tableData = state.tableData.filter((item: any) => item.phoneNumber !== row.phoneNumber);
+			}
+		})
+		.catch(() => {});
+};
+// 批量删除市民
+const onDelete = () => {
+	ElMessageBox.confirm(`您确定要删除选择的【${proTableRef.value.selectedList.length}】个市民?`, '提示', {
+		confirmButtonText: '确定',
+		cancelButtonText: '取消',
+		type: 'warning',
+		draggable: true,
+		autofocus: false,
+	})
+		.then(() => {
+			state.tableData = state.tableData.filter((item: any) => !proTableRef.value.selectedList.includes(item));
+		})
+		.catch(() => {});
+};
+// 清空选择
+const onClear = () => {
+	ElMessageBox.confirm('确定要清空?', '提示', {
+		confirmButtonText: '确定',
+		cancelButtonText: '取消',
+		type: 'warning',
+		draggable: true,
+		autofocus: false,
+	})
+		.then(() => {
+			proTableRef.value.clearSelection();
+			state.tableData = [];
+		})
+		.catch(() => {});
+};
+// 添加市民后
+const selectCitizen = (data: any) => {
+	state.tableData = removeDuplicate([...state.tableData, ...data], 'phoneNumber'); // 添加时去重
+	// 新添加的数据默认选中
+	nextTick(() => {
+		proTableRef.value.clearSelection();
+		const ids = data.map((item: any) => item.id);
+		state.tableData.forEach((row) => {
+			if (ids.includes(row.id)) {
+				proTableRef.value.element.toggleRowSelection(row, true);
+			}
+		});
+	});
+};
+// 保存
+const onSubmit = throttle(async (formEl: FormInstance | undefined) => {
+	if (!formEl) return;
+	await formEl.validate((valid: boolean) => {
+		if (!valid) return;
+		loading.value = true;
+		const request = {
+			...state.ruleForm,
+			classify: state.ruleForm.classifyArray.join(','),
+		};
+		orderLexiconAdd(request)
+			.then(() => {
+				ElMessage({
+					message: '操作成功',
+					type: 'success',
+				});
+				emit('updateList');
+			})
+			.catch((error) => {})
+			.finally(() => {
+				loading.value = false;
+				closeDialog();
+			});
+	});
+}, 300);
+// 暴露变量
+defineExpose({
+	openDialog,
+	closeDialog,
+});
+</script>

+ 108 - 0
src/views/auxiliary/smartCallOut/components/Task-detail.vue

@@ -0,0 +1,108 @@
+<template>
+  <el-dialog v-model="state.dialogVisible" draggable title="外呼明细" @close="close" destroy-on-close append-to-body>
+    <el-form :model="state.queryParams" ref="ruleFormRef" inline @submit.native.prevent>
+      <el-form-item label="市民姓名" prop="PhoneNumber">
+        <el-input v-model="state.queryParams.PhoneNumber" placeholder="请输入市民姓名" clearable @keyup.enter="handleQuery" />
+      </el-form-item>
+      <el-form-item label="联系电话" prop="Label">
+        <el-input v-model="state.queryParams.Label" placeholder="请输入市民联系电话" clearable @keyup.enter="handleQuery" />
+      </el-form-item>
+      <el-form-item>
+        <el-form-item label="外呼状态" prop="PushBusiness">
+          <el-select v-model="state.queryParams.PushBusiness" placeholder="请选择外呼状态" @change="handleQuery">
+            <el-option v-for="item in ePushBusinessData" :value="item.key" :key="item.key" :label="item.value" />
+          </el-select>
+        </el-form-item>
+        <el-button type="primary" @click="handleQuery" :loading="state.loading"> <SvgIcon name="ele-Search" class="mr5" />查询 </el-button>
+        <el-button @click="resetQuery(ruleFormRef)" class="default-button"> <SvgIcon name="ele-Refresh" class="mr5" />重置 </el-button>
+      </el-form-item>
+    </el-form>
+    <ProTable
+      ref="proTableRef"
+      :columns="columns"
+      :data="state.tableData"
+      :loading="state.loading"
+      :total="state.total"
+      v-model:page-index="state.queryParams.PageIndex"
+      v-model:page-size="state.queryParams.PageSize"
+      :tool-button="false"
+    >
+    </ProTable>
+  </el-dialog>
+</template>
+
+<script setup lang="tsx">
+import { computed, nextTick, reactive, ref } from 'vue';
+import { ElButton, ElInput, ElMessage, FormInstance } from 'element-plus';
+
+// 定义变量内容
+const state = reactive<any>({
+  dialogVisible: false,
+  queryParams: {
+    // 查询参数
+    PageIndex: 1,
+    PageSize: 10,
+    PhoneNumber: null,
+    Label: null,
+  },
+  tableData: [],
+});
+const ePushBusinessData = ref([])
+const ruleFormRef = ref<RefType>(null); // 表单ref
+/** 搜索按钮操作 */
+const handleQuery = () => {
+  state.queryParams.PageIndex = 1;
+  queryList();
+};
+// 获取列表
+const queryList = () => {
+  /*state.loading = true;
+  citizenList(state.queryParams)
+    .then((res) => {
+      state.loading = false;
+      state.tableData = res.result.items ?? [];
+      state.total = res.result.total ?? 0;
+    })
+    .finally(() => {
+      state.loading = false;
+    });*/
+};
+// 重置表单
+const resetQuery = (formEl: FormInstance | undefined) => {
+  if (!formEl) return;
+  formEl.resetFields();
+  queryList();
+};
+const proTableRef = ref<RefType>(); // 表格ref
+const canChoose = computed(() => {
+  return proTableRef.value?.selectedList.length;
+});
+// 表格配置项
+const columns = ref<any[]>([
+  { prop: 'phoneNumber', label: '市民姓名' },
+  { prop: 'label', label: '联系电话' },
+]);
+
+let loading = ref<boolean>(false); // 加载状态
+// 打开弹窗
+const openDialog = async () => {
+  try {
+    state.dialogVisible = true;
+  } catch (error) {
+    console.log(error);
+  }
+};
+// 关闭弹窗
+const closeDialog = () => {
+  state.dialogVisible = false;
+};
+const close = () => {
+  ruleFormRef.value?.resetFields();
+  ruleFormRef.value?.resetFields();
+};
+// 暴露变量
+defineExpose({
+  openDialog,
+  closeDialog,
+});
+</script>

+ 69 - 0
src/views/auxiliary/smartCallOut/components/Tem-add.vue

@@ -0,0 +1,69 @@
+<template>
+	<el-dialog title="新增外呼任务模板" v-model="state.dialogVisible" width="800px" draggable @close="close">
+		<el-form :model="state.ruleForm" ref="ruleFormRef" label-width="100px">
+			<el-form-item label="模板名称" prop="name" :rules="[{ required: true, message: '请输入模板名称', trigger: 'blur' }]">
+				<el-input v-model="state.ruleForm.name" placeholder="请输入模板名称" clearable></el-input>
+			</el-form-item>
+			<el-form-item label="模板内容" prop="content" :rules="[{ required: true, message: '请输入模板内容', trigger: 'blur' }]">
+				<el-input v-model="state.ruleForm.content" placeholder="请输入模板内容" type="textarea" :autosize="{ minRows: 4, maxRows: 8 }"></el-input>
+			</el-form-item>
+		</el-form>
+		<template #footer>
+			<span class="dialog-footer">
+				<el-button @click="closeDialog" class="default-button">取 消</el-button>
+				<el-button type="primary" @click="onSubmit(ruleFormRef)" :loading="state.loading">确 定 </el-button>
+			</span>
+		</template>
+	</el-dialog>
+</template>
+
+<script setup lang="ts" name="qualityLexiconAdd">
+import { reactive, ref } from 'vue';
+import { ElInput, ElMessage, ElMessageBox, FormInstance } from 'element-plus';
+// 定义子组件向父组件传值/事件
+const emit = defineEmits(['updateList']);
+
+// 定义变量内容
+const ruleFormRef = ref<FormInstance>();
+const state = reactive<any>({
+	dialogVisible: false, // 弹窗显示隐藏
+	ruleForm: {
+		name: '', // 模板名称
+		content: '', // 模板内容
+	},
+	loading: false, // 确定按钮loading
+});
+// 打开弹窗
+const openDialog = async () => {
+	try {
+		state.dialogVisible = true;
+	} catch (e) {
+		console.log(e);
+	}
+};
+// 关闭弹窗
+const closeDialog = () => {
+	state.dialogVisible = false;
+};
+const close = () => {
+	ruleFormRef.value?.clearValidate();
+	ruleFormRef.value?.resetFields();
+};
+// 保存
+const onSubmit = (formEl: FormInstance | undefined) => {
+	if (!formEl) return;
+	formEl.validate((valid: boolean) => {
+		if (!valid) return;
+		state.loading = true;
+		const request = {
+			...state.ruleForm,
+		};
+
+	});
+};
+// 暴露变量
+defineExpose({
+	openDialog,
+	closeDialog,
+});
+</script>

+ 69 - 0
src/views/auxiliary/smartCallOut/components/Tem-edit.vue

@@ -0,0 +1,69 @@
+<template>
+  <el-dialog title="编辑外呼任务模板" v-model="state.dialogVisible" width="800px" draggable @close="close">
+    <el-form :model="state.ruleForm" ref="ruleFormRef" label-width="100px">
+      <el-form-item label="模板名称" prop="name" :rules="[{ required: true, message: '请输入模板名称', trigger: 'blur' }]">
+        <el-input v-model="state.ruleForm.name" placeholder="请输入模板名称" clearable></el-input>
+      </el-form-item>
+      <el-form-item label="模板内容" prop="content" :rules="[{ required: true, message: '请输入模板内容', trigger: 'blur' }]">
+        <el-input v-model="state.ruleForm.content" placeholder="请输入模板内容" type="textarea" :autosize="{ minRows: 4, maxRows: 8 }"></el-input>
+      </el-form-item>
+    </el-form>
+    <template #footer>
+			<span class="dialog-footer">
+				<el-button @click="closeDialog" class="default-button">取 消</el-button>
+				<el-button type="primary" @click="onSubmit(ruleFormRef)" :loading="state.loading">确 定 </el-button>
+			</span>
+    </template>
+  </el-dialog>
+</template>
+
+<script setup lang="ts" name="qualityLexiconAdd">
+import { reactive, ref } from 'vue';
+import { ElInput, ElMessage, ElMessageBox, FormInstance } from 'element-plus';
+// 定义子组件向父组件传值/事件
+const emit = defineEmits(['updateList']);
+
+// 定义变量内容
+const ruleFormRef = ref<FormInstance>();
+const state = reactive<any>({
+  dialogVisible: false, // 弹窗显示隐藏
+  ruleForm: {
+    name: '', // 模板名称
+    content: '', // 模板内容
+  },
+  loading: false, // 确定按钮loading
+});
+// 打开弹窗
+const openDialog = async () => {
+  try {
+    state.dialogVisible = true;
+  } catch (e) {
+    console.log(e);
+  }
+};
+// 关闭弹窗
+const closeDialog = () => {
+  state.dialogVisible = false;
+};
+const close = () => {
+  ruleFormRef.value?.clearValidate();
+  ruleFormRef.value?.resetFields();
+};
+// 保存
+const onSubmit = (formEl: FormInstance | undefined) => {
+  if (!formEl) return;
+  formEl.validate((valid: boolean) => {
+    if (!valid) return;
+    state.loading = true;
+    const request = {
+      ...state.ruleForm,
+    };
+
+  });
+};
+// 暴露变量
+defineExpose({
+  openDialog,
+  closeDialog,
+});
+</script>

+ 83 - 41
src/views/auxiliary/smartCallOut/task.vue

@@ -2,17 +2,26 @@
   <div class="auxiliary-Smart-call-out-task-container layout-pd">
     <el-card shadow="never">
       <el-form :model="state.queryParams" ref="ruleFormRef" inline @submit.native.prevent>
-        <el-form-item label="市民联系方式" prop="PhoneNumber">
-          <el-input
-            v-model="state.queryParams.PhoneNumber"
-            placeholder="请输入市民联系方式"
-            clearable
-            @keyup.enter="handleQuery"
-            class="keyword-input"
-          />
+        <el-form-item label="任务名称" prop="PhoneNumber">
+          <el-input v-model="state.queryParams.PhoneNumber" placeholder="请输入任务名称" clearable @keyup.enter="handleQuery" class="keyword-input" />
+        </el-form-item>
+        <el-form-item label="任务状态" prop="PushBusiness">
+          <el-select v-model="state.queryParams.PushBusiness" placeholder="请选择任务状态" @change="handleQuery">
+            <el-option v-for="item in ePushBusinessData" :value="item.key" :key="item.key" :label="item.value" />
+          </el-select>
         </el-form-item>
-        <el-form-item label="市民标签" prop="Label">
-          <el-input v-model="state.queryParams.Label" placeholder="请输入市民标签" clearable @keyup.enter="handleQuery" class="keyword-input" />
+        <el-form-item label="创建时间" prop="crTime">
+          <el-date-picker
+            v-model="state.queryParams.crTime"
+            type="datetimerange"
+            unlink-panels
+            range-separator="至"
+            start-placeholder="开始时间"
+            end-placeholder="结束时间"
+            :shortcuts="shortcuts"
+            @change="timeStartChangeCr"
+            value-format="YYYY-MM-DD[T]HH:mm:ss"
+          />
         </el-form-item>
         <el-form-item>
           <el-button type="primary" @click="handleQuery" :loading="state.loading"> <SvgIcon name="ele-Search" class="mr5" />查询 </el-button>
@@ -21,11 +30,6 @@
       </el-form>
     </el-card>
     <el-card shadow="never">
-      <!--      <div class="mb20">
-        <el-button type="primary" @click="onLexiconDelete" v-waves v-auth="'auxiliary:citizen:delete'" :disabled="!multipleSelection.length">
-          <SvgIcon name="ele-Delete" class="mr5" />删除
-        </el-button>
-      </div>-->
       <!-- 表格 -->
       <ProTable
         ref="proTableRef"
@@ -37,17 +41,19 @@
         v-model:page-index="state.queryParams.PageIndex"
         v-model:page-size="state.queryParams.PageSize"
       >
+        <template #tableHeader="scope">
+          <el-button type="primary" @click="addTask" v-auth="'auxiliary:smartCallOut:add'"> <SvgIcon name="ele-Plus" class="mr5" />创建任务 </el-button>
+        </template>
         <!-- 表格操作 -->
         <template #operation="{ row }">
-          <el-button link type="primary" @click="onTagsRecord(row)" v-auth="'auxiliary:citizen:tag'" title="查看市民标签记录"> 标签记录 </el-button>
-          <el-button link type="primary" @click="onTagsEdit(row)" v-auth="'auxiliary:citizen:edit'" title="编辑市民画像"> 编辑 </el-button>
+          <el-button link type="primary" @click="onDetail(row)" title="外呼明细"> 外呼明细 </el-button>
+          <el-button link type="primary" @click="onEnd(row)" v-auth="'auxiliary:smartCallOut:end'" title="终止任务"> 终止任务 </el-button>
         </template>
       </ProTable>
     </el-card>
-    <!-- 标签记录   -->
-    <tags-record ref="tagsRecordRef" />
-    <!-- 编辑市民画像   -->
-    <tags-edit ref="TagsEditRef" @updateList="queryList" />
+    <!-- 创建任务   -->
+    <create-task ref="createTaskRef" />
+    <task-detail ref="taskDetailRef" />
   </div>
 </template>
 
@@ -55,36 +61,38 @@
 import { defineAsyncComponent, onMounted, reactive, ref } from 'vue';
 import { ElButton, ElMessage, ElMessageBox, FormInstance } from 'element-plus';
 import { formatDate } from '@/utils/formatTime';
-import { citizenDelete, citizenList } from '@/api/auxiliary/citizen';
+import { citizenList } from '@/api/auxiliary/citizen';
+import { shortcuts } from '@/utils/constants';
 
 // 引入组件
-const TagsRecord = defineAsyncComponent(() => import('@/views/auxiliary/citizen/components/Tags-record.vue')); // 标签记录
-const TagsEdit = defineAsyncComponent(() => import('@/views/auxiliary/citizen/components/Tags-edit.vue')); // 标签编辑
+const CreateTask = defineAsyncComponent(() => import('@/views/auxiliary/smartCallOut/components/Create-task.vue')); // 创建任务
+const TaskDetail = defineAsyncComponent(() => import('@/views/auxiliary/smartCallOut/components/Task-detail.vue')); // 任务详情
 
 const proTableRef = ref<RefType>(); // 表格ref
 // 表格配置项
 const columns = ref<any[]>([
-  { prop: 'phoneNumber', label: '市民联系方式', width: 200 },
-  { prop: 'label', label: '市民标签', width: 300 },
-  { prop: 'creatorName', label: '创建人' },
+  { prop: 'phoneNumber', label: '任务名称', width: 200 },
+  { prop: 'label', label: '任务状态', width: 200 },
+  { prop: 'creatorName', label: '外呼总量' },
   {
     prop: 'creationTime',
-    label: '创建时间',
+    label: '任务时间段',
     width: 170,
     render: (scope) => {
       return <span>{formatDate(scope.row.creationTime, 'YYYY-mm-dd HH:MM:SS')}</span>;
     },
   },
-  { prop: 'lastModificationName', label: '更新人' },
+  { prop: 'lastModificationName', label: '创建人' },
+  { prop: 'lastModificationName', label: '创建部门' },
   {
     prop: 'lastModificationTime',
-    label: '更新时间',
+    label: '创建时间',
     width: 170,
     render: (scope) => {
       return <span>{formatDate(scope.row.lastModificationTime, 'YYYY-mm-dd HH:MM:SS')}</span>;
     },
   },
-  { prop: 'operation', label: '操作', fixed: 'right', width: 140, align: 'center' },
+  { prop: 'operation', label: '操作', fixed: 'right', width: 160, align: 'center' },
 ]);
 // 定义变量内容
 const state = reactive({
@@ -95,11 +103,27 @@ const state = reactive({
     PageSize: 10,
     PhoneNumber: null,
     Label: null,
+    crTime: [],
   },
   total: 0, // 总条数
   tableData: [], // 表格数据
 });
 const ruleFormRef = ref<RefType>(null); // 表单ref
+const handleTimeChange = (val: string[], startKey: string, endKey: string) => {
+  if (val) {
+    state.queryParams[startKey] = val[0];
+    state.queryParams[endKey] = val[1];
+  } else {
+    state.queryParams[startKey] = null;
+    state.queryParams[endKey] = null;
+  }
+  handleQuery();
+};
+// 受理时间
+const timeStartChangeCr = (val: string[]) => {
+  handleTimeChange(val, 'StartTime', 'EndTime');
+  queryList();
+};
 /** 搜索按钮操作 */
 const handleQuery = () => {
   state.queryParams.PageIndex = 1;
@@ -107,7 +131,7 @@ const handleQuery = () => {
 };
 // 获取列表
 const queryList = () => {
-  state.loading = true;
+  /*state.loading = true;
   citizenList(state.queryParams)
     .then((res) => {
       state.loading = false;
@@ -116,7 +140,7 @@ const queryList = () => {
     })
     .finally(() => {
       state.loading = false;
-    });
+    });*/
 };
 // 重置表单
 const resetQuery = (formEl: FormInstance | undefined) => {
@@ -124,16 +148,34 @@ const resetQuery = (formEl: FormInstance | undefined) => {
   formEl.resetFields();
   queryList();
 };
-// 标签记录
-const tagsRecordRef = ref<RefType>();
-const onTagsRecord = (row: any) => {
-  tagsRecordRef.value.openDialog(row);
+// 创建任务
+const createTaskRef = ref<RefType>();
+const addTask = () => {
+  createTaskRef.value.openDialog();
 };
-// 编辑标签
-const TagsEditRef = ref<RefType>();
-const onTagsEdit = (row: any) => {
-  TagsEditRef.value.openDialog(row);
+// 任务明细
+const taskDetailRef = ref<RefType>();
+const onDetail = (row: any) => {
+  taskDetailRef.value.openDialog(row);
+};
+// 终止任务
+const onEnd = (row: any) => {
+  ElMessageBox.confirm('确定终止任务?', '提示', {
+    confirmButtonText: '确定',
+    cancelButtonText: '取消',
+    type: 'warning',
+    draggable: true,
+    autofocus: false,
+  })
+    .then(() => {
+      ElMessage({
+        type: 'success',
+        message: '终止任务成功',
+      });
+    })
+    .catch(() => {});
 };
+const ePushBusinessData = ref([]);
 // 页面加载时
 onMounted(() => {
   queryList();

+ 179 - 103
src/views/auxiliary/smartCallOut/template.vue

@@ -1,54 +1,58 @@
 <template>
-  <div class="auxiliary-Smart-call-out-template-container layout-pd">
-    <el-card shadow="never">
-      <el-form :model="state.queryParams" ref="ruleFormRef" inline @submit.native.prevent>
-        <el-form-item label="市民联系方式" prop="PhoneNumber">
-          <el-input
-            v-model="state.queryParams.PhoneNumber"
-            placeholder="请输入市民联系方式"
-            clearable
-            @keyup.enter="handleQuery"
-            class="keyword-input"
-          />
-        </el-form-item>
-        <el-form-item label="市民标签" prop="Label">
-          <el-input v-model="state.queryParams.Label" placeholder="请输入市民标签" clearable @keyup.enter="handleQuery" class="keyword-input" />
-        </el-form-item>
-        <el-form-item>
-          <el-button type="primary" @click="handleQuery" :loading="state.loading"> <SvgIcon name="ele-Search" class="mr5" />查询 </el-button>
-          <el-button @click="resetQuery(ruleFormRef)" class="default-button"> <SvgIcon name="ele-Refresh" class="mr5" />重置 </el-button>
-        </el-form-item>
-      </el-form>
-    </el-card>
-    <el-card shadow="never">
-      <!--      <div class="mb20">
-        <el-button type="primary" @click="onLexiconDelete" v-waves v-auth="'auxiliary:citizen:delete'" :disabled="!multipleSelection.length">
-          <SvgIcon name="ele-Delete" class="mr5" />删除
-        </el-button>
-      </div>-->
-      <!-- 表格 -->
-      <ProTable
-        ref="proTableRef"
-        :columns="columns"
-        :data="state.tableData"
-        @updateTable="queryList"
-        :loading="state.loading"
-        :total="state.total"
-        v-model:page-index="state.queryParams.PageIndex"
-        v-model:page-size="state.queryParams.PageSize"
-      >
-        <!-- 表格操作 -->
-        <template #operation="{ row }">
-          <el-button link type="primary" @click="onTagsRecord(row)" v-auth="'auxiliary:citizen:tag'" title="查看市民标签记录"> 标签记录 </el-button>
-          <el-button link type="primary" @click="onTagsEdit(row)" v-auth="'auxiliary:citizen:edit'" title="编辑市民画像"> 编辑 </el-button>
-        </template>
-      </ProTable>
-    </el-card>
-    <!-- 标签记录   -->
-    <tags-record ref="tagsRecordRef" />
-    <!-- 编辑市民画像   -->
-    <tags-edit ref="TagsEditRef" @updateList="queryList" />
-  </div>
+	<div class="auxiliary-Smart-call-out-template-container layout-pd">
+		<el-card shadow="never">
+			<el-form :model="state.queryParams" ref="ruleFormRef" inline @submit.native.prevent>
+				<el-form-item label="模板标题" prop="Label">
+					<el-input v-model="state.queryParams.Label" placeholder="请输入模板标题" clearable @keyup.enter="handleQuery" class="keyword-input" />
+				</el-form-item>
+				<el-form-item label="创建时间" prop="crTime">
+					<el-date-picker
+						v-model="state.queryParams.crTime"
+						type="datetimerange"
+						unlink-panels
+						range-separator="至"
+						start-placeholder="开始时间"
+						end-placeholder="结束时间"
+						:shortcuts="shortcuts"
+						@change="timeStartChangeCr"
+						value-format="YYYY-MM-DD[T]HH:mm:ss"
+					/>
+				</el-form-item>
+				<el-form-item>
+					<el-button type="primary" @click="handleQuery" :loading="state.loading"> <SvgIcon name="ele-Search" class="mr5" />查询 </el-button>
+					<el-button @click="resetQuery(ruleFormRef)" class="default-button"> <SvgIcon name="ele-Refresh" class="mr5" />重置 </el-button>
+				</el-form-item>
+			</el-form>
+		</el-card>
+		<el-card shadow="never">
+			<!-- 表格 -->
+			<ProTable
+				ref="proTableRef"
+				:columns="columns"
+				:data="state.tableData"
+				@updateTable="queryList"
+				:loading="state.loading"
+				:total="state.total"
+				v-model:page-index="state.queryParams.PageIndex"
+				v-model:page-size="state.queryParams.PageSize"
+			>
+				<template #tableHeader="scope">
+					<el-button type="primary" @click="onAdd" v-auth="'auxiliary:smartCallOut:tem:add'">
+						<SvgIcon name="ele-Plus" class="mr5" /> 新增模板
+					</el-button>
+				</template>
+				<!-- 表格操作 -->
+				<template #operation="{ row }">
+					<el-button link type="primary" @click="onEdit(row)" v-auth="'auxiliary:smartCallOut:tem:edit'" title="编辑模板"> 编辑 </el-button>
+					<el-button link type="primary" @click="onDelete(row)" v-auth="'auxiliary:smartCallOut:tem:delete'" title="删除模板"> 删除 </el-button>
+				</template>
+			</ProTable>
+		</el-card>
+		<!-- 新增模板   -->
+		<tem-add ref="temAddRef" @updateList="queryList" />
+		<!-- 编辑模板   -->
+		<tem-edit ref="temEditRef" @updateList="queryList" />
+	</div>
 </template>
 
 <script lang="tsx" setup name="auxiliarySmartCallOutTemplate">
@@ -56,86 +60,158 @@ import { defineAsyncComponent, onMounted, reactive, ref } from 'vue';
 import { ElButton, ElMessage, ElMessageBox, FormInstance } from 'element-plus';
 import { formatDate } from '@/utils/formatTime';
 import { citizenDelete, citizenList } from '@/api/auxiliary/citizen';
+import { shortcuts } from '@/utils/constants';
+import { auth } from "@/utils/authFunction";
 
 // 引入组件
-const TagsRecord = defineAsyncComponent(() => import('@/views/auxiliary/citizen/components/Tags-record.vue')); // 标签记录
-const TagsEdit = defineAsyncComponent(() => import('@/views/auxiliary/citizen/components/Tags-edit.vue')); // 标签编辑
+const TemAdd = defineAsyncComponent(() => import('@/views/auxiliary/smartCallOut/components/Tem-add.vue')); // 新建模板
+const TemEdit = defineAsyncComponent(() => import('@/views/auxiliary/smartCallOut/components/Tem-edit.vue')); // 编辑标签
 
 const proTableRef = ref<RefType>(); // 表格ref
 // 表格配置项
 const columns = ref<any[]>([
-  { prop: 'phoneNumber', label: '市民联系方式', width: 200 },
-  { prop: 'label', label: '市民标签', width: 300 },
-  { prop: 'creatorName', label: '创建人' },
+	{ prop: 'phoneNumber', label: '标题'},
+	{ prop: 'label', label: '关联外呼任务'},
   {
-    prop: 'creationTime',
-    label: '创建时间',
-    width: 170,
+    prop: 'isEnable',
+    label: '是否启用',
     render: (scope) => {
-      return <span>{formatDate(scope.row.creationTime, 'YYYY-mm-dd HH:MM:SS')}</span>;
+      return (
+        <>
+          {auth('quality:template:edit') ? (
+            <el-switch
+              model-value={scope.row.isEnable}
+              active-text="启用"
+              inactive-text="禁用"
+              active-value={1}
+              inactive-value={0}
+              onClick={() => changeIsEnable(scope.row)}
+              inline-prompt
+            />
+          ) : (
+            <span>{scope.row.isEnable === 1 ? '启用' : '禁用'}</span>
+          )}
+        </>
+      );
     },
   },
-  { prop: 'lastModificationName', label: '更新人' },
-  {
-    prop: 'lastModificationTime',
-    label: '更新时间',
-    width: 170,
-    render: (scope) => {
-      return <span>{formatDate(scope.row.lastModificationTime, 'YYYY-mm-dd HH:MM:SS')}</span>;
-    },
-  },
-  { prop: 'operation', label: '操作', fixed: 'right', width: 140, align: 'center' },
+	{ prop: 'creatorName', label: '创建人' },
+  { prop: 'creatorName', label: '创建部门' },
+	{
+		prop: 'creationTime',
+		label: '创建时间',
+		width: 170,
+		render: (scope) => {
+			return <span>{formatDate(scope.row.creationTime, 'YYYY-mm-dd HH:MM:SS')}</span>;
+		},
+	},
+	{ prop: 'operation', label: '操作', fixed: 'right', width: 140, align: 'center' },
 ]);
 // 定义变量内容
 const state = reactive({
-  loading: false, // 加载状态
-  queryParams: {
-    // 查询参数
-    PageIndex: 1,
-    PageSize: 10,
-    PhoneNumber: null,
-    Label: null,
-  },
-  total: 0, // 总条数
-  tableData: [], // 表格数据
+	loading: false, // 加载状态
+	queryParams: {
+		// 查询参数
+		PageIndex: 1,
+		PageSize: 10,
+		PhoneNumber: null,
+		Label: null,
+	},
+	total: 0, // 总条数
+	tableData: [], // 表格数据
 });
 const ruleFormRef = ref<RefType>(null); // 表单ref
 /** 搜索按钮操作 */
 const handleQuery = () => {
-  state.queryParams.PageIndex = 1;
-  queryList();
+	state.queryParams.PageIndex = 1;
+	queryList();
+};
+const handleTimeChange = (val: string[], startKey: string, endKey: string) => {
+	if (val) {
+		state.queryParams[startKey] = val[0];
+		state.queryParams[endKey] = val[1];
+	} else {
+		state.queryParams[startKey] = null;
+		state.queryParams[endKey] = null;
+	}
+	handleQuery();
+};
+// 创建时间
+const timeStartChangeCr = (val: string[]) => {
+	handleTimeChange(val, 'StartTime', 'EndTime');
+	queryList();
 };
 // 获取列表
 const queryList = () => {
-  state.loading = true;
-  citizenList(state.queryParams)
-    .then((res) => {
-      state.loading = false;
-      state.tableData = res.result.items ?? [];
-      state.total = res.result.total ?? 0;
-    })
-    .finally(() => {
-      state.loading = false;
-    });
+	/*state.loading = true;
+	citizenList(state.queryParams)
+		.then((res) => {
+			state.loading = false;
+			state.tableData = res.result.items ?? [];
+			state.total = res.result.total ?? 0;
+		})
+		.finally(() => {
+			state.loading = false;
+		});*/
 };
 // 重置表单
 const resetQuery = (formEl: FormInstance | undefined) => {
-  if (!formEl) return;
-  formEl.resetFields();
-  queryList();
+	if (!formEl) return;
+	formEl.resetFields();
+	queryList();
+};
+// 新增模板
+const temAddRef = ref<RefType>();
+const onAdd = (row: any) => {
+  temAddRef.value.openDialog();
 };
-// 标签记录
-const tagsRecordRef = ref<RefType>();
-const onTagsRecord = (row: any) => {
-  tagsRecordRef.value.openDialog(row);
+// 编辑模板
+const temEditRef = ref<RefType>();
+const onEdit = (row: any) => {
+  temEditRef.value.openDialog(row);
 };
-// 编辑标签
-const TagsEditRef = ref<RefType>();
-const onTagsEdit = (row: any) => {
-  TagsEditRef.value.openDialog(row);
+// 删除模板
+const onDelete = (row: any) => {
+	ElMessageBox.confirm('确定要删除当前模板?', '提示', {
+		confirmButtonText: '确定',
+		cancelButtonText: '取消',
+		type: 'warning',
+	}).then(() => {
+
+	}).catch(()=>{
+
+  })
+};
+// 启用和禁用
+const changeIsEnable = (row: any) => {
+  ElMessageBox.confirm(`您确定要${row.isEnable === 1 ? '禁用' : '启用'}:【${row.name}】模板,是否继续?`, '提示', {
+    confirmButtonText: '确认',
+    cancelButtonText: '取消',
+    type: 'warning',
+    draggable: true,
+    cancelButtonClass: 'default-button',
+    autofocus: false,
+  })
+    .then(() => {
+      // const isEnable = row.isEnable === 1 ? 0 : 1;
+      // const request = {
+      //   ...row,
+      //   isEnable: isEnable,
+      // };
+      // templateUpdate(request)
+      //   .then(() => {
+      //     ElMessage.success('操作成功');
+      //     queryList();
+      //   })
+      //   .catch(() => {
+      //     queryList();
+      //   });
+    })
+    .catch(() => {
+    });
 };
 // 页面加载时
 onMounted(() => {
-  queryList();
+	queryList();
 });
 </script>

+ 123 - 0
src/views/auxiliary/smsTask/components/Add-citizen.vue

@@ -0,0 +1,123 @@
+<template>
+	<el-dialog v-model="state.dialogVisible" draggable title="选择市民" @close="close" destroy-on-close append-to-body>
+		<el-form :model="state.queryParams" ref="ruleFormRef" inline @submit.native.prevent>
+			<el-form-item label="市民姓名" prop="PhoneNumber">
+				<el-input v-model="state.queryParams.PhoneNumber" placeholder="请输入市民姓名" clearable @keyup.enter="handleQuery" />
+			</el-form-item>
+			<el-form-item label="联系电话" prop="Label">
+				<el-input v-model="state.queryParams.Label" placeholder="请输入市民联系电话" clearable @keyup.enter="handleQuery" />
+			</el-form-item>
+			<el-form-item>
+				<el-button type="primary" @click="handleQuery" :loading="state.loading"> <SvgIcon name="ele-Search" class="mr5" />查询 </el-button>
+				<el-button @click="resetQuery(ruleFormRef)" class="default-button"> <SvgIcon name="ele-Refresh" class="mr5" />重置 </el-button>
+			</el-form-item>
+		</el-form>
+		<ProTable
+			ref="proTableRef"
+			:columns="columns"
+			:data="state.tableData"
+			:loading="state.loading"
+			:total="state.total"
+			v-model:page-index="state.queryParams.PageIndex"
+			v-model:page-size="state.queryParams.PageSize"
+			:tool-button="false"
+      @updateTable="queryList"
+		>
+		</ProTable>
+		<template #footer>
+			<span class="dialog-footer">
+				<el-button @click="closeDialog" class="default-button">取 消</el-button>
+				<el-button type="primary" @click="onSubmit" :loading="loading" :disabled="!canChoose">确 定</el-button>
+			</span>
+		</template>
+	</el-dialog>
+</template>
+
+<script setup lang="tsx">
+import { computed, nextTick, onMounted, reactive, ref } from "vue";
+import { ElButton, ElInput, ElMessage, FormInstance } from 'element-plus';
+import { citizenList } from '@/api/auxiliary/citizen';
+
+// 定义子组件向父组件传值/事件
+const emit = defineEmits(['selectCitizen']);
+
+// 定义变量内容
+const state = reactive<any>({
+	dialogVisible: false,
+	queryParams: {
+		// 查询参数
+		PageIndex: 1,
+		PageSize: 10,
+		PhoneNumber: null,
+		Label: null,
+	},
+	tableData: [],
+});
+
+const ruleFormRef = ref<RefType>(null); // 表单ref
+/** 搜索按钮操作 */
+const handleQuery = () => {
+	state.queryParams.PageIndex = 1;
+	queryList();
+};
+// 获取列表
+const queryList = () => {
+	/*state.loading = true;
+	citizenList(state.queryParams)
+		.then((res) => {
+			state.loading = false;
+			state.tableData = res.result.items ?? [];
+			state.total = res.result.total ?? 0;
+		})
+		.finally(() => {
+			state.loading = false;
+		});*/
+};
+// 重置表单
+const resetQuery = (formEl: FormInstance | undefined) => {
+	if (!formEl) return;
+	formEl.resetFields();
+	queryList();
+};
+const proTableRef = ref<RefType>(); // 表格ref
+const canChoose = computed(() => {
+	return proTableRef.value?.selectedList.length;
+});
+// 表格配置项
+const columns = ref<any[]>([
+	{ type: 'selection', fixed: 'left', width: 55, align: 'center' },
+	{ prop: 'name', label: '市民姓名' },
+	{ prop: 'phoneNumber', label: '联系电话' },
+]);
+
+let loading = ref<Boolean>(false); // 加载状态
+// 打开弹窗
+const openDialog = async () => {
+	try {
+		state.dialogVisible = true;
+	} catch (error) {
+		console.log(error);
+	}
+};
+// 关闭弹窗
+const closeDialog = () => {
+	state.dialogVisible = false;
+};
+const close = () => {
+	ruleFormRef.value?.resetFields();
+	ruleFormRef.value?.resetFields();
+};
+// 新增
+const onSubmit = () => {
+	emit('selectCitizen', proTableRef.value?.selectedList);
+  closeDialog()
+};
+onMounted(()=>{
+  queryList();
+})
+// 暴露变量
+defineExpose({
+	openDialog,
+	closeDialog,
+});
+</script>

+ 214 - 0
src/views/auxiliary/smsTask/components/Create-task.vue

@@ -0,0 +1,214 @@
+<template>
+	<el-dialog v-model="state.dialogVisible" width="60%" draggable title="创建任务" @close="close" append-to-body destroy-on-close>
+		<el-form :model="state.ruleForm" label-width="120px" ref="ruleFormRef">
+			<el-row :gutter="10">
+				<el-col :xs="24" :sm="12" :md="12" :lg="12" :xl="12">
+					<el-form-item label="任务名称" prop="tag" :rules="[{ required: true, message: '请输入任务名称', trigger: 'blur' }]">
+						<el-input v-model="state.ruleForm.tag" placeholder="请输入任务名称" clearable></el-input>
+					</el-form-item>
+				</el-col>
+				<el-col :xs="24" :sm="12" :md="12" :lg="12" :xl="12">
+					<el-form-item label="计划发送时间" prop="time" :rules="[{ required: true, message: '请选择计划发送时间', trigger: 'change' }]">
+						<el-date-picker
+							v-model="state.ruleForm.time"
+							type="datetime"
+							placeholder="请选择计划发送时间"
+							class="w100"
+							value-format="YYYY-MM-DD[T]HH:mm:ss"
+						/>
+					</el-form-item>
+				</el-col>
+				<el-col :xs="24" :sm="24" :md="24" :lg="24" :xl="24">
+					<el-form-item label="短信内容" prop="remark" :rules="[{ required: true, message: '请输入短信内容', trigger: 'blur' }]">
+						<el-input v-model="state.ruleForm.remark" placeholder="请输入短信内容" type="textarea" :autosize="{ minRows: 4, maxRows: 8 }"></el-input>
+					</el-form-item>
+				</el-col>
+			</el-row>
+			<el-divider />
+			<ProTable
+				ref="proTableRef"
+				:columns="columns"
+				:data="state.tableData"
+				:loading="state.loading"
+				:pagination="false"
+				:tool-button="false"
+				max-height="400px"
+				row-key="id"
+			>
+				<template #tableHeader="scope">
+					<el-button type="primary" @click="addCitizen"> <SvgIcon name="ele-Plus" class="mr5" />添加市民 </el-button>
+					<el-button type="primary" @click="importCitizen"> <SvgIcon name="ele-Upload" class="mr5" />导入市民 </el-button>
+					<el-button type="primary" @click="temDownload"> <SvgIcon name="ele-Download" class="mr5" />模板下载 </el-button>
+					<el-button type="primary" @click="onDelete" :disabled="!scope.isSelected"> <SvgIcon name="ele-Delete" class="mr5" />批量删除 </el-button>
+					<el-button type="primary" @click="onClear"> <SvgIcon name="ele-CircleClose" class="mr5" /> 清空 </el-button>
+				</template>
+				<!-- 表格操作 -->
+				<template #operation="{ row }">
+					<el-button link type="primary" @click="onDel(row)" title="删除"> 删除 </el-button>
+				</template>
+			</ProTable>
+		</el-form>
+		<template #footer>
+			<span class="dialog-footer">
+				<el-button @click="closeDialog" class="default-button">取 消</el-button>
+				<el-button type="primary" @click="onSubmit(ruleFormRef)" :loading="loading" :disabled="!canChoose">确 定</el-button>
+			</span>
+		</template>
+	</el-dialog>
+	<citizen-add ref="addCitizenRef" @selectCitizen="selectCitizen" />
+</template>
+
+<script setup lang="ts">
+import { computed, defineAsyncComponent, nextTick, reactive, ref } from 'vue';
+import { ElButton, ElInput, ElMessage, ElMessageBox, FormInstance } from 'element-plus';
+import { throttle } from '@/utils/tools';
+import { orderLexiconAdd } from '@/api/auxiliary/orderLexicon';
+import { removeDuplicate } from '@/utils/arrayOperation';
+
+const CitizenAdd = defineAsyncComponent(() => import('@/views/auxiliary/smsTask/components/Add-citizen.vue')); // 创建任务
+
+// 定义子组件向父组件传值/事件
+const emit = defineEmits(['updateList']);
+// 定义变量内容
+const state = reactive<any>({
+	dialogVisible: false,
+	ruleForm: {
+		tag: '', // 工单关键词
+		classifyArray: [], // 标签分类
+		isEnable: 1, // 是否启用
+		synonym: '', // 违禁同义词
+		remark: '', // 备注说明
+	},
+	tableData: [], // 表格内容
+});
+let loading = ref<boolean>(false); // 加载状态
+// 打开弹窗
+const ruleFormRef = ref<RefType>();
+const openDialog = async () => {
+	ruleFormRef.value?.resetFields();
+	try {
+		state.dialogVisible = true;
+	} catch (error) {
+		console.log(error);
+	}
+};
+// 关闭弹窗
+const closeDialog = () => {
+	state.dialogVisible = false;
+};
+const close = () => {
+	ruleFormRef.value?.resetFields();
+	ruleFormRef.value?.resetFields();
+};
+// 表格配置项
+const proTableRef = ref<RefType>(); // 表格ref
+const canChoose = computed(() => {
+	return proTableRef.value?.selectedList.length;
+});
+const columns = ref<any[]>([
+	{ type: 'selection', fixed: 'left', width: 55, align: 'center' },
+	{ prop: 'name', label: '市民姓名' },
+	{ prop: 'phoneNumber', label: '联系电话' },
+	{ prop: 'operation', label: '操作', fixed: 'right', width: 80, align: 'center' },
+]);
+// 添加市民
+const addCitizenRef = ref<RefType>();
+const addCitizen = () => {
+	addCitizenRef.value.openDialog();
+};
+// 导入市民
+const importCitizen = () => {};
+// 模板下载
+const temDownload = () => {};
+// 单个删除
+const onDel = (row: any) => {
+	ElMessageBox.confirm('确定要删除?', '提示', {
+		confirmButtonText: '确定',
+		cancelButtonText: '取消',
+		type: 'warning',
+		draggable: true,
+		autofocus: false,
+	})
+		.then(() => {
+			if (row.id) {
+				state.tableData = state.tableData.filter((item: any) => item.id !== row.id);
+			} else {
+				state.tableData = state.tableData.filter((item: any) => item.phoneNumber !== row.phoneNumber);
+			}
+		})
+		.catch(() => {});
+};
+// 批量删除市民
+const onDelete = () => {
+	ElMessageBox.confirm(`您确定要删除选择的【${proTableRef.value.selectedList.length}】个市民?`, '提示', {
+		confirmButtonText: '确定',
+		cancelButtonText: '取消',
+		type: 'warning',
+		draggable: true,
+		autofocus: false,
+	})
+		.then(() => {
+			state.tableData = state.tableData.filter((item: any) => !proTableRef.value.selectedList.includes(item));
+		})
+		.catch(() => {});
+};
+// 清空选择
+const onClear = () => {
+	ElMessageBox.confirm('确定要清空?', '提示', {
+		confirmButtonText: '确定',
+		cancelButtonText: '取消',
+		type: 'warning',
+		draggable: true,
+		autofocus: false,
+	})
+		.then(() => {
+			proTableRef.value.clearSelection();
+			state.tableData = [];
+		})
+		.catch(() => {});
+};
+// 添加市民后
+const selectCitizen = (data: any) => {
+	state.tableData = removeDuplicate([...state.tableData, ...data], 'phoneNumber'); // 添加时去重
+	// 新添加的数据默认选中
+	nextTick(() => {
+		proTableRef.value.clearSelection();
+    const ids = data.map((item: any) => item.id);
+		state.tableData.forEach((row) => {
+			if (ids.includes(row.id)) {
+				proTableRef.value.element.toggleRowSelection(row, true);
+			}
+		});
+	});
+};
+// 保存
+const onSubmit = throttle(async (formEl: FormInstance | undefined) => {
+	if (!formEl) return;
+	await formEl.validate((valid: boolean) => {
+		if (!valid) return;
+		loading.value = true;
+		const request = {
+			...state.ruleForm,
+			classify: state.ruleForm.classifyArray.join(','),
+		};
+		orderLexiconAdd(request)
+			.then(() => {
+				ElMessage({
+					message: '操作成功',
+					type: 'success',
+				});
+				emit('updateList');
+			})
+			.catch((error) => {})
+			.finally(() => {
+				loading.value = false;
+				closeDialog();
+			});
+	});
+}, 300);
+// 暴露变量
+defineExpose({
+	openDialog,
+	closeDialog,
+});
+</script>

+ 103 - 0
src/views/auxiliary/smsTask/components/Task-detail.vue

@@ -0,0 +1,103 @@
+<template>
+  <el-dialog v-model="state.dialogVisible" draggable title="短信明细" @close="close" destroy-on-close append-to-body>
+    <el-form :model="state.queryParams" ref="ruleFormRef" inline @submit.native.prevent>
+      <el-form-item label="市民姓名" prop="PhoneNumber">
+        <el-input v-model="state.queryParams.PhoneNumber" placeholder="请输入市民姓名" clearable @keyup.enter="handleQuery" />
+      </el-form-item>
+      <el-form-item label="联系电话" prop="Label">
+        <el-input v-model="state.queryParams.Label" placeholder="请输入市民联系电话" clearable @keyup.enter="handleQuery" />
+      </el-form-item>
+      <el-form-item>
+        <el-button type="primary" @click="handleQuery" :loading="state.loading"> <SvgIcon name="ele-Search" class="mr5" />查询 </el-button>
+        <el-button @click="resetQuery(ruleFormRef)" class="default-button"> <SvgIcon name="ele-Refresh" class="mr5" />重置 </el-button>
+      </el-form-item>
+    </el-form>
+    <ProTable
+      ref="proTableRef"
+      :columns="columns"
+      :data="state.tableData"
+      :loading="state.loading"
+      :total="state.total"
+      v-model:page-index="state.queryParams.PageIndex"
+      v-model:page-size="state.queryParams.PageSize"
+      :tool-button="false"
+    >
+    </ProTable>
+  </el-dialog>
+</template>
+
+<script setup lang="tsx">
+import { computed, nextTick, reactive, ref } from 'vue';
+import { ElButton, ElInput, ElMessage, FormInstance } from 'element-plus';
+
+// 定义变量内容
+const state = reactive<any>({
+  dialogVisible: false,
+  queryParams: {
+    // 查询参数
+    PageIndex: 1,
+    PageSize: 10,
+    PhoneNumber: null,
+    Label: null,
+  },
+  tableData: [],
+});
+
+const ruleFormRef = ref<RefType>(null); // 表单ref
+/** 搜索按钮操作 */
+const handleQuery = () => {
+  state.queryParams.PageIndex = 1;
+  queryList();
+};
+// 获取列表
+const queryList = () => {
+  /*state.loading = true;
+  citizenList(state.queryParams)
+    .then((res) => {
+      state.loading = false;
+      state.tableData = res.result.items ?? [];
+      state.total = res.result.total ?? 0;
+    })
+    .finally(() => {
+      state.loading = false;
+    });*/
+};
+// 重置表单
+const resetQuery = (formEl: FormInstance | undefined) => {
+  if (!formEl) return;
+  formEl.resetFields();
+  queryList();
+};
+const proTableRef = ref<RefType>(); // 表格ref
+const canChoose = computed(() => {
+  return proTableRef.value?.selectedList.length;
+});
+// 表格配置项
+const columns = ref<any[]>([
+  { prop: 'phoneNumber', label: '市民姓名' },
+  { prop: 'label', label: '联系电话' },
+]);
+
+let loading = ref<boolean>(false); // 加载状态
+// 打开弹窗
+const openDialog = async () => {
+  try {
+    state.dialogVisible = true;
+  } catch (error) {
+    console.log(error);
+  }
+};
+// 关闭弹窗
+const closeDialog = () => {
+  state.dialogVisible = false;
+};
+const close = () => {
+  ruleFormRef.value?.resetFields();
+  ruleFormRef.value?.resetFields();
+};
+// 暴露变量
+defineExpose({
+  openDialog,
+  closeDialog,
+});
+</script>

+ 82 - 40
src/views/auxiliary/smsTask/index.vue

@@ -2,17 +2,26 @@
 	<div class="auxiliary-SMS-task-container layout-pd">
 		<el-card shadow="never">
 			<el-form :model="state.queryParams" ref="ruleFormRef" inline @submit.native.prevent>
-				<el-form-item label="市民联系方式" prop="PhoneNumber">
-					<el-input
-						v-model="state.queryParams.PhoneNumber"
-						placeholder="请输入市民联系方式"
-						clearable
-						@keyup.enter="handleQuery"
-						class="keyword-input"
-					/>
+				<el-form-item label="任务名称" prop="PhoneNumber">
+					<el-input v-model="state.queryParams.PhoneNumber" placeholder="请输入任务名称" clearable @keyup.enter="handleQuery" class="keyword-input" />
+				</el-form-item>
+				<el-form-item label="任务状态" prop="PushBusiness">
+					<el-select v-model="state.queryParams.PushBusiness" placeholder="请选择任务状态" @change="handleQuery">
+						<el-option v-for="item in ePushBusinessData" :value="item.key" :key="item.key" :label="item.value" />
+					</el-select>
 				</el-form-item>
-				<el-form-item label="市民标签" prop="Label">
-					<el-input v-model="state.queryParams.Label" placeholder="请输入市民标签" clearable @keyup.enter="handleQuery" class="keyword-input" />
+				<el-form-item label="创建时间" prop="crTime">
+					<el-date-picker
+						v-model="state.queryParams.crTime"
+						type="datetimerange"
+						unlink-panels
+						range-separator="至"
+						start-placeholder="开始时间"
+						end-placeholder="结束时间"
+						:shortcuts="shortcuts"
+						@change="timeStartChangeCr"
+						value-format="YYYY-MM-DD[T]HH:mm:ss"
+					/>
 				</el-form-item>
 				<el-form-item>
 					<el-button type="primary" @click="handleQuery" :loading="state.loading"> <SvgIcon name="ele-Search" class="mr5" />查询 </el-button>
@@ -21,11 +30,6 @@
 			</el-form>
 		</el-card>
 		<el-card shadow="never">
-			<!--      <div class="mb20">
-        <el-button type="primary" @click="onLexiconDelete" v-waves v-auth="'auxiliary:citizen:delete'" :disabled="!multipleSelection.length">
-          <SvgIcon name="ele-Delete" class="mr5" />删除
-        </el-button>
-      </div>-->
 			<!-- 表格 -->
 			<ProTable
 				ref="proTableRef"
@@ -37,17 +41,19 @@
 				v-model:page-index="state.queryParams.PageIndex"
 				v-model:page-size="state.queryParams.PageSize"
 			>
+				<template #tableHeader="scope">
+					<el-button type="primary" @click="addTask" v-auth="'auxiliary:smsTask:add'"> <SvgIcon name="ele-Plus" class="mr5" />创建任务 </el-button>
+				</template>
 				<!-- 表格操作 -->
 				<template #operation="{ row }">
-					<el-button link type="primary" @click="onTagsRecord(row)" v-auth="'auxiliary:citizen:tag'" title="查看市民标签记录"> 标签记录 </el-button>
-					<el-button link type="primary" @click="onTagsEdit(row)" v-auth="'auxiliary:citizen:edit'" title="编辑市民画像"> 编辑 </el-button>
+					<el-button link type="primary" @click="onDetail(row)" title="短信明细"> 短信明细 </el-button>
+					<el-button link type="primary" @click="onEnd(row)" v-auth="'auxiliary:smsTask:end'" title="终止任务"> 终止任务 </el-button>
 				</template>
 			</ProTable>
 		</el-card>
-		<!-- 标签记录   -->
-		<tags-record ref="tagsRecordRef" />
-		<!-- 编辑市民画像   -->
-		<tags-edit ref="TagsEditRef" @updateList="queryList" />
+		<!-- 创建任务   -->
+		<create-task ref="createTaskRef" />
+    <task-detail ref="taskDetailRef" />
 	</div>
 </template>
 
@@ -56,35 +62,37 @@ import { defineAsyncComponent, onMounted, reactive, ref } from 'vue';
 import { ElButton, ElMessage, ElMessageBox, FormInstance } from 'element-plus';
 import { formatDate } from '@/utils/formatTime';
 import { citizenDelete, citizenList } from '@/api/auxiliary/citizen';
+import { shortcuts } from '@/utils/constants';
 
 // 引入组件
-const TagsRecord = defineAsyncComponent(() => import('@/views/auxiliary/citizen/components/Tags-record.vue')); // 标签记录
-const TagsEdit = defineAsyncComponent(() => import('@/views/auxiliary/citizen/components/Tags-edit.vue')); // 标签编辑
+const CreateTask = defineAsyncComponent(() => import('@/views/auxiliary/smsTask/components/Create-task.vue')); // 创建任务
+const TaskDetail = defineAsyncComponent(() => import('@/views/auxiliary/smsTask/components/Task-detail.vue')); // 任务详情
 
 const proTableRef = ref<RefType>(); // 表格ref
 // 表格配置项
 const columns = ref<any[]>([
-	{ prop: 'phoneNumber', label: '市民联系方式', width: 200 },
-	{ prop: 'label', label: '市民标签', width: 300 },
-	{ prop: 'creatorName', label: '创建人' },
+	{ prop: 'phoneNumber', label: '任务名称', width: 200 },
+	{ prop: 'label', label: '任务状态', width: 200 },
+	{ prop: 'creatorName', label: '短信总量' },
 	{
 		prop: 'creationTime',
-		label: '创建时间',
+		label: '计划发送时间',
 		width: 170,
 		render: (scope) => {
 			return <span>{formatDate(scope.row.creationTime, 'YYYY-mm-dd HH:MM:SS')}</span>;
 		},
 	},
-	{ prop: 'lastModificationName', label: '更新人' },
+	{ prop: 'lastModificationName', label: '创建人' },
+	{ prop: 'lastModificationName', label: '创建部门' },
 	{
 		prop: 'lastModificationTime',
-		label: '更新时间',
+		label: '创建时间',
 		width: 170,
 		render: (scope) => {
 			return <span>{formatDate(scope.row.lastModificationTime, 'YYYY-mm-dd HH:MM:SS')}</span>;
 		},
 	},
-	{ prop: 'operation', label: '操作', fixed: 'right', width: 140, align: 'center' },
+	{ prop: 'operation', label: '操作', fixed: 'right', width: 160, align: 'center' },
 ]);
 // 定义变量内容
 const state = reactive({
@@ -95,11 +103,27 @@ const state = reactive({
 		PageSize: 10,
 		PhoneNumber: null,
 		Label: null,
+		crTime: [],
 	},
 	total: 0, // 总条数
 	tableData: [], // 表格数据
 });
 const ruleFormRef = ref<RefType>(null); // 表单ref
+const handleTimeChange = (val: string[], startKey: string, endKey: string) => {
+	if (val) {
+		state.queryParams[startKey] = val[0];
+		state.queryParams[endKey] = val[1];
+	} else {
+		state.queryParams[startKey] = null;
+		state.queryParams[endKey] = null;
+	}
+	handleQuery();
+};
+// 创建时间
+const timeStartChangeCr = (val: string[]) => {
+	handleTimeChange(val, 'StartTime', 'EndTime');
+	queryList();
+};
 /** 搜索按钮操作 */
 const handleQuery = () => {
 	state.queryParams.PageIndex = 1;
@@ -107,7 +131,7 @@ const handleQuery = () => {
 };
 // 获取列表
 const queryList = () => {
-	state.loading = true;
+	/*state.loading = true;
 	citizenList(state.queryParams)
 		.then((res) => {
 			state.loading = false;
@@ -116,7 +140,7 @@ const queryList = () => {
 		})
 		.finally(() => {
 			state.loading = false;
-		});
+		});*/
 };
 // 重置表单
 const resetQuery = (formEl: FormInstance | undefined) => {
@@ -124,16 +148,34 @@ const resetQuery = (formEl: FormInstance | undefined) => {
 	formEl.resetFields();
 	queryList();
 };
-// 标签记录
-const tagsRecordRef = ref<RefType>();
-const onTagsRecord = (row: any) => {
-	tagsRecordRef.value.openDialog(row);
+// 创建任务
+const createTaskRef = ref<RefType>();
+const addTask = () => {
+	createTaskRef.value.openDialog();
 };
-// 编辑标签
-const TagsEditRef = ref<RefType>();
-const onTagsEdit = (row: any) => {
-	TagsEditRef.value.openDialog(row);
+// 短信明细
+const taskDetailRef = ref<RefType>();
+const onDetail = (row: any) => {
+  taskDetailRef.value.openDialog(row);
+};
+// 终止任务
+const onEnd = (row: any) => {
+	ElMessageBox.confirm('确定终止任务?', '提示', {
+		confirmButtonText: '确定',
+		cancelButtonText: '取消',
+		type: 'warning',
+		draggable: true,
+		autofocus: false,
+	})
+		.then(() => {
+			ElMessage({
+				type: 'success',
+				message: '终止任务成功',
+			});
+		})
+		.catch(() => {});
 };
+const ePushBusinessData = ref([]);
 // 页面加载时
 onMounted(() => {
 	queryList();

+ 1 - 1
src/views/business/visit/smart.vue

@@ -23,7 +23,7 @@
 				v-model:page-size="state.queryParams.PageSize"
 			>
 				<template #tableHeader="scope">
-					<el-button type="primary" @click="onAddVisit" v-auth="'business:visit:smart:add'"> <SvgIcon name="ele-Plus" class="mr5" />新增 </el-button>
+					<el-button type="primary" @click="onAddVisit" v-auth="'business:visit:smart:add'"> <SvgIcon name="ele-Plus" class="mr5" /> 创建任务 </el-button>
 				</template>
 				<!-- 表格操作 -->
 				<template #operation="{ row }">

+ 4 - 3
src/views/statistics/call/detailTalkTime.vue

@@ -110,9 +110,7 @@ const queryList = () => {
 	}
 	let beginDate = null;
 	let endDate = null;
-	if (historyParams.beginDate) {
-		state.queryParams.crTime = [historyParams.beginDate, historyParams.endDate];
-	}
+
 	if (state.queryParams?.crTime) {
 		beginDate = state.queryParams?.crTime[0];
 		endDate = state.queryParams?.crTime[1];
@@ -190,6 +188,9 @@ const showSearch = computed(() => {
 	return historyParams.showSearch;
 });
 onMounted(() => {
+  if (historyParams.beginDate) {
+    state.queryParams.crTime = [historyParams.beginDate, historyParams.endDate];
+  }
 	getBaseInfo();
 	queryList();
 });

+ 2 - 1
src/views/statistics/call/talkTime.vue

@@ -31,6 +31,7 @@
 				</el-form-item>
 			</el-form>
 		</el-card>
+<!--    :toolButton="['refresh', 'setting', 'exportCurrent', 'exportAll']"-->
 		<el-card shadow="never">
 			<ProTable
 				ref="proTableRef"
@@ -41,7 +42,7 @@
 				:pagination="false"
 				border
 				show-summary
-				:toolButton="['refresh', 'setting', 'exportCurrent', 'exportAll']"
+
 				@exportCurrent="exportCurrent"
 				@exportAll="exportAll"
 			>

+ 138 - 0
src/views/statistics/order/secondHandle.vue

@@ -0,0 +1,138 @@
+<template>
+  <div class="statistics-department-delay-container layout-pd">
+    <!-- 搜索  -->
+    <el-card shadow="never">
+      <el-form :model="state.queryParams" ref="ruleFormRef" @submit.native.prevent inline>
+        <el-form-item label="延期部门" prop="OrgName">
+          <el-input v-model="state.queryParams.OrgName" placeholder="部门名称" clearable @keyup.enter="handleQuery" class="keyword-input" />
+        </el-form-item>
+        <el-form-item label="时间段" prop="crTime">
+          <el-date-picker
+            v-model="state.queryParams.crTime"
+            type="daterange"
+            unlink-panels
+            range-separator="至"
+            start-placeholder="开始时间"
+            end-placeholder="结束时间"
+            :shortcuts="shortcuts"
+            @change="handleQuery"
+            value-format="YYYY-MM-DD"
+            :clearable="false"
+          />
+        </el-form-item>
+        <el-form-item>
+          <el-button type="primary" @click="handleQuery" :loading="state.loading"> <SvgIcon name="ele-Search" class="mr5" />查询 </el-button>
+          <el-button @click="resetQuery(ruleFormRef)" class="default-button" :loading="state.loading">
+            <SvgIcon name="ele-Refresh" class="mr5" />重置
+          </el-button>
+        </el-form-item>
+      </el-form>
+    </el-card>
+    <el-card shadow="never">
+      <ProTable
+        ref="proTableRef"
+        :columns="columns"
+        :data="state.tableData"
+        @updateTable="queryList"
+        :loading="state.loading"
+        show-summary
+        border
+        :pagination="false"
+        role-key="orgCode"
+      >
+      </ProTable>
+    </el-card>
+  </div>
+</template>
+<script setup lang="tsx" name="statisticsOrderSecondHandle">
+import { onMounted, reactive, ref } from 'vue';
+import { FormInstance } from 'element-plus';
+import { departmentDelay } from '@/api/statistics/department';
+import { defaultDate, shortcuts } from "@/utils/constants";
+import { useRouter } from "vue-router";
+import { guid } from "@/utils/tools";
+
+// 表格配置项
+const columns = ref<any[]>([
+  { type: 'index', fixed: 'left', width: 55, label: '序号', align: 'center' },
+  { prop: 'orgName', label: '部门名称', align: 'center',render: (scope) => {
+      return (
+        <el-button type="primary" link onClick={() => linkDetail(scope.row,'1')}>
+          {scope.row.orgName}
+        </el-button>
+      );
+    } },
+  { prop: 'allTotal', label: '数量', align: 'center',render: (scope) => {
+      return (
+        <el-button type="primary" link onClick={() => linkDetail(scope.row,'4')}>
+          {scope.row.allTotal}
+        </el-button>
+      );
+    }, },
+]);
+// 定义变量内容
+const ruleFormRef = ref<RefType>(); // 表单ref
+const state = reactive({
+  queryParams: {
+    // 查询条件
+    OrgName: null, // 关键词
+    crTime: defaultDate, // 时间默认今天开始到今天结束
+  },
+  tableData: [], //表单
+  loading: false, // 加载
+  total: 0, // 总数
+});
+/** 搜索按钮操作 */
+const handleQuery = () => {
+  // state.queryParams.PageIndex = 1;
+  queryList();
+};
+/** 获取列表 */
+const queryList = () => {
+  /*state.loading = true;
+  let StartTime = null;
+  let EndTime = null;
+  if (state.queryParams?.crTime) {
+    StartTime = state.queryParams?.crTime[0];
+    EndTime = state.queryParams?.crTime[1];
+  }
+  const request = {
+    StartTime,
+    EndTime,
+    OrgName: state.queryParams.OrgName,
+  };
+  departmentDelay(request)
+    .then((res: any) => {
+      state.tableData = res.result ?? [];
+      state.loading = false;
+    })
+    .catch(() => {
+      state.loading = false;
+    });*/
+};
+/** 重置按钮操作 */
+const resetQuery = (formEl: FormInstance | undefined) => {
+  if (!formEl) return;
+  formEl.resetFields();
+  queryList();
+};
+// 跳转详情
+const router = useRouter();
+const linkDetail = (row: any,type:string) => {
+  router.push({
+    name: 'statisticsDepartmentDetailDelay',
+    params: {
+      id: guid(),
+    },
+    state: {
+      StartTime: state.queryParams?.crTime[0],
+      EndTime: state.queryParams?.crTime[1],
+      OrgCode: row.orgCode,
+      Type: type,
+    },
+  });
+};
+onMounted(() => {
+  queryList();
+});
+</script>

+ 384 - 0
src/views/statistics/order/shSatisfied.vue

@@ -0,0 +1,384 @@
+<template>
+  <div class="statistics-department-satisfied-container layout-pd">
+    <!-- 搜索  -->
+    <el-card shadow="never">
+      <el-form :model="state.queryParams" ref="ruleFormRef" @submit.native.prevent inline>
+        <el-form-item label="部门名称" prop="OrgName">
+          <el-input v-model="state.queryParams.OrgName" placeholder="部门名称" clearable @keyup.enter="handleQuery" class="keyword-input" />
+        </el-form-item>
+        <el-form-item label="时间段" prop="crTime">
+          <el-date-picker
+            v-model="state.queryParams.crTime"
+            type="daterange"
+            unlink-panels
+            range-separator="至"
+            start-placeholder="开始时间"
+            end-placeholder="结束时间"
+            :shortcuts="shortcuts"
+            @change="handleQuery"
+            value-format="YYYY-MM-DD"
+            :clearable="false"
+          />
+        </el-form-item>
+        <!--				<el-form-item label="类型" prop="TypeId">
+                  <el-select v-model="state.queryParams.TypeId" placeholder="类型" @change="handleQuery">
+                    <el-option label="办件结果" value="1" />
+                    <el-option label="办件态度" value="2" />
+                  </el-select>
+                </el-form-item>-->
+        <el-form-item label="电话线路" prop="LineNum">
+          <el-input v-model="state.queryParams.LineNum" placeholder="电话线路" clearable @keyup.enter="handleQuery" class="keyword-input" />
+        </el-form-item>
+        <el-form-item>
+          <el-button type="primary" @click="handleQuery" :loading="state.loading"> <SvgIcon name="ele-Search" class="mr5" />查询 </el-button>
+          <el-button @click="resetQuery(ruleFormRef)" class="default-button" :loading="state.loading">
+            <SvgIcon name="ele-Refresh" class="mr5" />重置
+          </el-button>
+        </el-form-item>
+      </el-form>
+    </el-card>
+    <el-card shadow="never">
+      <ProTable
+        ref="proTableRef"
+        :columns="columns"
+        :data="state.tableData"
+        @updateTable="queryList"
+        :loading="state.loading"
+        show-summary
+        border
+        :pagination="false"
+        :summary-method="getSummaries"
+      >
+        <template #orgName="{ row }">
+          <el-button link type="primary" @click="onDetailOrg(row)" v-if="!['市直合计', '区县合计'].includes(row.orgName)">{{
+              row.orgName
+            }}</el-button>
+          <span v-else>{{ row.orgName }}</span>
+        </template>
+        <template #verySatisfiedCount="{ row }">
+          <el-button
+            link
+            type="primary"
+            @click="onDetail(row.verySatisfiedKey, row, '非常满意')"
+            v-if="!['市直合计', '区县合计'].includes(row.orgName)"
+          >{{ row.verySatisfiedCount }}</el-button
+          >
+          <span v-else>{{ row.verySatisfiedCount }}</span>
+        </template>
+        <template #satisfiedCount="{ row }">
+          <el-button link type="primary" @click="onDetail(row.satisfiedKey, row, '满意')" v-if="!['市直合计', '区县合计'].includes(row.orgName)">{{
+              row.satisfiedCount
+            }}</el-button>
+          <span v-else>{{ row.satisfiedCount }}</span>
+        </template>
+        <template #regardedAsSatisfiedCount="{ row }">
+          <el-button
+            link
+            type="primary"
+            @click="onDetail(row.regardedAsSatisfiedKey, row, '视为满意')"
+            v-if="!['市直合计', '区县合计'].includes(row.orgName)"
+          >{{ row.regardedAsSatisfiedCount }}</el-button
+          >
+          <span v-else>{{ row.regardedAsSatisfiedCount }}</span>
+        </template>
+        <template #defaultSatisfiedCount="{ row }">
+          <el-button
+            link
+            type="primary"
+            @click="onDetail(row.defaultSatisfiedKey, row, '默认满意')"
+            v-if="!['市直合计', '区县合计'].includes(row.orgName)"
+          >{{ row.defaultSatisfiedCount }}</el-button
+          >
+          <span v-else>{{ row.defaultSatisfiedCount }}</span>
+        </template>
+        <template #noSatisfiedCount="{ row }">
+          <el-button
+            link
+            type="primary"
+            @click="onDetail(row.noSatisfiedKey, row, '不满意')"
+            v-if="!['市直合计', '区县合计'].includes(row.orgName)"
+          >{{ row.noSatisfiedCount }}</el-button
+          >
+          <span v-else>{{ row.noSatisfiedCount }}</span>
+        </template>
+        <template #noEvaluateCount="{ row }">
+          <el-button
+            link
+            type="primary"
+            @click="onDetail(row.noEvaluateKey, row, '未作评价')"
+            v-if="!['市直合计', '区县合计'].includes(row.orgName)"
+          >{{ row.noEvaluateCount }}</el-button
+          >
+          <span v-else>{{ row.noEvaluateCount }}</span>
+        </template>
+        <template #noPutThroughCount="{ row }">
+          <el-button
+            link
+            type="primary"
+            @click="onDetail(row.noPutThroughKey, row, '未接通')"
+            v-if="!['市直合计', '区县合计'].includes(row.orgName)"
+          >{{ row.noPutThroughCount }}</el-button
+          >
+          <span v-else>{{ row.noPutThroughCount }}</span>
+        </template>
+      </ProTable>
+    </el-card>
+  </div>
+</template>
+<script setup lang="tsx" name="statisticsOrderShSatisfied">
+import { onMounted, reactive, ref } from 'vue';
+import { FormInstance } from 'element-plus';
+import { departmentSatisfaction } from '@/api/statistics/department';
+import { defaultDate, shortcuts } from "@/utils/constants";
+import { useRouter } from 'vue-router';
+import { guid } from "@/utils/tools";
+
+// 表格配置项
+const columns = ref<any[]>([
+  { type: 'index', fixed: 'left', width: 55, label: '序号', align: 'center' },
+  { prop: 'orgName', label: '部门名称', minWidth: 200 },
+  { prop: 'orgTypeText', label: '部门类别', minWidth: 120 },
+  { prop: 'totalSumCount', label: '小计' },
+  {
+    prop: 'totalSumRate',
+    label: '总满意率',
+    minWidth: 120,
+    render: ({ row }) => {
+      return `${row.totalSumRate}%`;
+    },
+  },
+  { prop: 'verySatisfiedCount', label: '非常满意', minWidth: 120 },
+  {
+    prop: 'verySatisfiedRate',
+    label: '非常满意率',
+    minWidth: 120,
+    render: ({ row }) => {
+      return `${row.verySatisfiedRate}%`;
+    },
+  },
+  { prop: 'satisfiedCount', label: '满意', minWidth: 120 },
+  {
+    prop: 'satisfiedRate',
+    label: '满意率',
+    minWidth: 120,
+    render: ({ row }) => {
+      return `${row.satisfiedRate}%`;
+    },
+  },
+  { prop: 'regardedAsSatisfiedCount', label: '视为满意', minWidth: 120 },
+  {
+    prop: 'regardedAsSatisfiedRate',
+    label: '视为满意率',
+    minWidth: 120,
+    render: ({ row }) => {
+      return `${row.regardedAsSatisfiedRate}%`;
+    },
+  },
+  { prop: 'defaultSatisfiedCount', label: '默认满意', minWidth: 120 },
+  {
+    prop: 'defaultSatisfiedRate',
+    label: '默认满意率',
+    minWidth: 120,
+    render: ({ row }) => {
+      return `${row.defaultSatisfiedRate}%`;
+    },
+  },
+  { prop: 'noSatisfiedCount', label: '不满意', minWidth: 120 },
+  {
+    prop: 'noSatisfiedRate',
+    label: '不满意率',
+    minWidth: 120,
+    render: ({ row }) => {
+      return `${row.noSatisfiedRate}%`;
+    },
+  },
+  { prop: 'noEvaluateCount', label: '未作评价', minWidth: 120 },
+  {
+    prop: 'noEvaluateRate',
+    label: '未作评价率',
+    minWidth: 120,
+    render: ({ row }) => {
+      return `${row.noEvaluateRate}%`;
+    },
+  },
+  { prop: 'noPutThroughCount', label: '未接通', minWidth: 120 },
+  {
+    prop: 'noPutThroughRate',
+    label: '未接通率',
+    minWidth: 120,
+    render: ({ row }) => {
+      return `${row.noPutThroughRate}%`;
+    },
+  },
+]);
+// 定义变量内容
+const ruleFormRef = ref<RefType>(); // 表单ref
+const state = reactive({
+  queryParams: {
+    // 查询条件
+    PageIndex: 1,
+    PageSize: 10,
+    TypeId: '1', //
+    LineNum: null,
+    crTime: defaultDate, // 时间默认今天开始到今天结束
+  },
+  tableData: [], //表单
+  loading: false, // 加载
+  total: 0, // 总数
+  totalCount: {},
+});
+/** 搜索按钮操作 */
+const handleQuery = () => {
+  // state.queryParams.PageIndex = 1;
+  queryList();
+};
+/** 获取列表 */
+const queryList = () => {
+  /*state.loading = true;
+  let StartDate = null;
+  let EndDate = null;
+  if (state.queryParams?.crTime) {
+    StartDate = state.queryParams?.crTime[0];
+    EndDate = state.queryParams?.crTime[1];
+  }
+  const request = {
+    StartDate,
+    EndDate,
+    TypeId: state.queryParams.TypeId,
+    LineNum: state.queryParams.LineNum,
+  };
+  departmentSatisfaction(request)
+    .then((res: any) => {
+      state.tableData = res.result?.dataList ?? [];
+      if (res.result.dataList.length) {
+        state.tableData.push(res.result.citySumModel);
+        state.tableData.push(res.result.countySumModel);
+      }
+      state.totalCount = res.result.sumModel;
+      state.loading = false;
+    })
+    .catch((err: any) => {
+      state.loading = false;
+    });*/
+}
+/** 重置按钮操作 */
+const resetQuery = (formEl: FormInstance | undefined) => {
+  if (!formEl) return;
+  formEl.resetFields();
+  queryList();
+}
+// 合计
+const getSummaries = (param: any) => {
+  const { columns } = param;
+  const sums: string[] = [];
+  columns.forEach((column: { property: string }, index: number) => {
+    if (index === 0) {
+      sums[index] = '合计';
+      return;
+    }
+    switch (column.property) {
+      case 'totalSumCount':
+        sums[index] = state.totalCount?.totalSumCount;
+        break;
+      case 'totalSumRate':
+        sums[index] = `${state.totalCount?.totalSumRate}%`;
+        break;
+      case 'verySatisfiedCount':
+        sums[index] = state.totalCount?.verySatisfiedCount;
+        break;
+      case 'verySatisfiedRate':
+        sums[index] = `${state.totalCount?.verySatisfiedRate}%`;
+        break;
+      case 'satisfiedCount':
+        sums[index] = state.totalCount?.satisfiedCount;
+        break;
+      case 'satisfiedRate':
+        sums[index] = `${state.totalCount?.satisfiedRate}%`;
+        break;
+      case 'regardedAsSatisfiedCount':
+        sums[index] = state.totalCount?.regardedAsSatisfiedCount;
+        break;
+      case 'regardedAsSatisfiedRate':
+        sums[index] = `${state.totalCount?.regardedAsSatisfiedRate}%`;
+        break;
+      case 'defaultSatisfiedCount':
+        sums[index] = state.totalCount?.defaultSatisfiedCount;
+        break;
+      case 'defaultSatisfiedRate':
+        sums[index] = `${state.totalCount?.defaultSatisfiedRate}%`;
+        break;
+      case 'noSatisfiedCount':
+        sums[index] = state.totalCount?.noSatisfiedCount;
+        break;
+      case 'noSatisfiedRate':
+        sums[index] = `${state.totalCount?.noSatisfiedRate}%`;
+        break;
+      case 'noEvaluateCount':
+        sums[index] = state.totalCount?.noEvaluateCount;
+        break;
+      case 'noEvaluateRate':
+        sums[index] = `${state.totalCount?.noEvaluateRate}%`;
+        break;
+      case 'noPutThroughCount':
+        sums[index] = state.totalCount?.noPutThroughCount;
+        break;
+      case 'noPutThroughRate':
+        sums[index] = `${state.totalCount?.noPutThroughRate}%`;
+        break;
+      default:
+        sums[index] = '';
+        break;
+    }
+  });
+  return sums;
+};
+const router = useRouter();
+// 点击部门名称
+const onDetailOrg = (row: any) => {
+  let StartDate = null;
+  let EndDate = null;
+  if (state.queryParams?.crTime) {
+    StartDate = state.queryParams?.crTime[0];
+    EndDate = state.queryParams?.crTime[1];
+  }
+  router.push({
+    name: 'statisticsDepartmentSatisfiedOrg',
+    state: {
+      StartDate,
+      EndDate,
+      OrgCode: row.orgCode,
+      TypeId: state.queryParams.TypeId,
+      LineNum: state.queryParams.LineNum,
+    },
+    params: {
+      key: guid()
+    },
+  });
+};
+// 点击数字
+const onDetail = (key: string, row, type: string) => {
+  let StartDate = null;
+  let EndDate = null;
+  if (state.queryParams?.crTime) {
+    StartDate = state.queryParams?.crTime[0];
+    EndDate = state.queryParams?.crTime[1];
+  }
+  router.push({
+    name: 'statisticsDepartmentSatisfiedDetail',
+    params: {
+      key: guid()
+    },
+    state: {
+      StartDate,
+      EndDate,
+      OrgCode: row.orgCode,
+      TypeId: state.queryParams.TypeId,
+      LineNum: state.queryParams.LineNum,
+      DateValue: key,
+    },
+  });
+};
+onMounted(() => {
+  queryList();
+});
+</script>

+ 58 - 0
src/views/todo/seats/accept/Copy.vue

@@ -0,0 +1,58 @@
+<template>
+	<ProTable
+		ref="proTableRef"
+		:columns="columns"
+		:data="state.tableData"
+		@updateTable="queryList"
+		:loading="state.loading"
+		:total="state.total"
+		v-model:page-index="state.queryParams.PageIndex"
+		v-model:page-size="state.queryParams.PageSize"
+		:key="Math.random()"
+    :tool-button="false"
+	>
+		<template #tableHeader="scope">
+			<el-button type="primary" @click="queryList" :loading="state.loading">刷新 </el-button>
+		</template>
+		<template #title="{ row }">
+			<order-detail :order="row" @updateList="queryList">{{ row.title }}</order-detail>
+		</template>
+	</ProTable>
+</template>
+<script setup lang="tsx" name="acceptCopyOrder">
+import { defineAsyncComponent, reactive, ref } from 'vue';
+import { formatDate } from '@/utils/formatTime';
+// 引入组件
+const OrderDetail = defineAsyncComponent(() => import('@/components/OrderDetail/index.vue')); // 工单详情
+// 定义变量内容
+const state = reactive({
+  queryParams:{
+    PageIndex:1,
+    PageSize:10
+  },
+	tableData: [], //表单
+	loading: false, // 加载
+	total: 0, // 总数
+});
+const columns = ref<any[]>([
+	{ prop: 'title', label: '工单标题' },
+	{
+		prop: 'creationTime',
+		label: '生成时间',
+		width: 170,
+		render: (scope) => {
+			return <span>{formatDate(scope.row.creationTime, 'YYYY-mm-dd HH:MM:SS')}</span>;
+		},
+	},
+]);
+/** 获取列表 */
+const queryList = async () => {
+	try {
+		state.loading = true;
+
+		state.loading = false;
+	} catch (e) {
+		state.loading = false;
+	}
+};
+</script>

파일 크기가 너무 크기때문에 변경 상태를 표시하지 않습니다.
+ 543 - 514
src/views/todo/seats/accept/index.vue


이 변경점에서 너무 많은 파일들이 변경되어 몇몇 파일들은 표시되지 않았습니다.