Smart-visit-add.vue 8.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264
  1. <template>
  2. <el-dialog v-model="state.dialogVisible" width="60%" draggable title="新增智能回访任务" @close="close" append-to-body destroy-on-close>
  3. <el-divider content-position="left" class="mb30">
  4. <el-text tag="b" size="large"> 回访任务内容 </el-text>
  5. </el-divider>
  6. <el-form :model="state.ruleForm" label-width="90px" ref="ruleFormRef" v-loading="state.loading">
  7. <el-row :gutter="10">
  8. <el-col :xs="24" :sm="12" :md="12" :lg="12" :xl="12">
  9. <el-form-item label="任务名称" prop="name" :rules="[{ required: true, message: '请填写任务名称', trigger: 'blur' }]">
  10. <el-input v-model="state.ruleForm.name" placeholder="请填写任务名称" clearable></el-input>
  11. </el-form-item>
  12. </el-col>
  13. <el-col :xs="24" :sm="12" :md="12" :lg="12" :xl="12">
  14. <el-form-item label="时间段" prop="crTime" :rules="[{ required: true, message: '请选择时间段', trigger: 'change' }]">
  15. <el-date-picker
  16. v-model="state.ruleForm.crTime"
  17. type="datetimerange"
  18. unlink-panels
  19. range-separator="至"
  20. start-placeholder="开始时间"
  21. end-placeholder="结束时间"
  22. :shortcuts="shortcuts"
  23. value-format="YYYY-MM-DD[T]HH:mm:ss"
  24. :default-time="defaultTimeStartEnd"
  25. />
  26. </el-form-item>
  27. </el-col>
  28. <el-col :xs="24" :sm="12" :md="12" :lg="12" :xl="12">
  29. <el-form-item label="节日禁呼" prop="festivalBan" :rules="[{ required: true, message: '请选择节日禁呼', trigger: 'change' }]">
  30. <el-radio-group v-model="state.ruleForm.festivalBan">
  31. <el-radio :label="1">是</el-radio>
  32. <el-radio :label="0">否</el-radio>
  33. </el-radio-group>
  34. </el-form-item>
  35. </el-col>
  36. </el-row>
  37. </el-form>
  38. <el-divider content-position="left" class="mb30">
  39. <el-text tag="b" size="large"> 回访任务名单 </el-text>
  40. </el-divider>
  41. <el-form :model="state.queryParams" ref="queryFormRef" @submit.native.prevent>
  42. <el-row :gutter="20">
  43. <el-col :xs="24" :sm="12" :md="12" :lg="12" :xl="8">
  44. <el-form-item label="工单标题" prop="Title">
  45. <el-input v-model="state.queryParams.Title" placeholder="工单标题" clearable @keyup.enter="queryList" />
  46. </el-form-item>
  47. </el-col>
  48. <el-col :xs="24" :sm="12" :md="12" :lg="12" :xl="8">
  49. <el-form-item label="工单编码" prop="No">
  50. <el-input v-model="state.queryParams.No" placeholder="工单编码" clearable @keyup.enter="queryList" />
  51. </el-form-item>
  52. </el-col>
  53. <el-col :xs="24" :sm="12" :md="12" :lg="12" :xl="8">
  54. <el-form-item label="受理类型" prop="AcceptTypes">
  55. <el-select
  56. v-model="state.queryParams.AcceptTypes"
  57. placeholder="请选择受理类型"
  58. multiple
  59. clearable
  60. class="w100"
  61. collapse-tags
  62. collapse-tags-tooltip
  63. :max-collapse-tags="2"
  64. >
  65. <el-option v-for="item in state.acceptTypeOptions" :value="item.dicDataValue" :key="item.dicDataValue" :label="item.dicDataName" />
  66. </el-select>
  67. </el-form-item>
  68. </el-col>
  69. <el-col :xs="24" :sm="12" :md="12" :lg="12" :xl="8">
  70. <el-form-item label="热点分类" prop="HotspotIds">
  71. <hot-spot-select
  72. v-model="state.queryParams.HotspotIds"
  73. class="w100"
  74. :hotspotExternal="state.hotspotExternal"
  75. show-checkbox
  76. ref="hotSpotRef"
  77. @confirm="queryList"
  78. />
  79. </el-form-item>
  80. </el-col>
  81. <el-col :xs="24" :sm="12" :md="12" :lg="12" :xl="8">
  82. <el-form-item>
  83. <el-button type="primary" @click="queryList" :loading="state.loading"> <SvgIcon name="ele-Search" class="mr5" />查询 </el-button>
  84. <el-button @click="resetQuery(queryFormRef)" class="default-button" :loading="state.loading">
  85. <SvgIcon name="ele-Refresh" class="mr5" />重置
  86. </el-button>
  87. </el-form-item>
  88. </el-col>
  89. </el-row>
  90. </el-form>
  91. <ProTable ref="proTableRef" :columns="columns" :data="state.tableData" @updateTable="queryList" :loading="state.loading" :pagination="false">
  92. <template #title="{ row }">
  93. <order-detail :order="row.order" @updateList="queryList">{{ row.order?.title }}</order-detail>
  94. </template>
  95. </ProTable>
  96. <template #footer>
  97. <span class="dialog-footer">
  98. <el-button @click="state.dialogVisible = false" class="default-button">取 消</el-button>
  99. <el-button type="primary" @click="onSubmit(ruleFormRef)" :loading="state.loading" :disabled="!canChoose">确 定</el-button>
  100. </span>
  101. </template>
  102. </el-dialog>
  103. </template>
  104. <script setup lang="tsx">
  105. import { formatDate } from '@/utils/formatTime';
  106. import { ElMessage, FormInstance } from 'element-plus';
  107. import { reactive, ref, defineAsyncComponent, computed } from 'vue';
  108. import { getSmartVisitRecord } from '@/api/smartVisit';
  109. import { defaultTimeStartEnd, shortcuts } from "@/utils/constants";
  110. import { smartVisitAdd, smartVisitBaseData } from '@/api/smartVisit';
  111. const OrderDetail = defineAsyncComponent(() => import('@/components/OrderDetail/index.vue')); // 工单详情
  112. const HotSpotSelect = defineAsyncComponent(() => import('@/components/Hotspot/index.vue')); // 选择热点
  113. const emit = defineEmits(['updateList']);
  114. const state = reactive({
  115. queryParams: {
  116. Title: null,
  117. No: null,
  118. AcceptTypes: [],
  119. HotspotIds: [],
  120. },
  121. tableData: [], //表格
  122. loading: false, // 加载
  123. dialogVisible: false, // 弹窗
  124. ruleForm: {
  125. name: '',
  126. crTime: [],
  127. festivalBan: 1,
  128. }, // 表单数据
  129. hotspotExternal: [],
  130. acceptTypeOptions: [],
  131. });
  132. const columns = ref<any[]>([
  133. { type: 'selection', fixed: 'left', width: 55, align: 'center' },
  134. { prop: 'order.no', label: '工单编码', width: 150 },
  135. {
  136. prop: 'title',
  137. label: '标题',
  138. width: 300,
  139. },
  140. { prop: 'order.sourceChannel', label: '来源方式' },
  141. { prop: 'visitStateText', label: '回访状态' },
  142. { prop: 'order.acceptType', label: '受理类型', width: 150 },
  143. { prop: 'order.hotspotName', label: '热点分类', width: 100 },
  144. { prop: 'order.actualHandleStepName', label: '办理节点', width: 150 },
  145. {
  146. prop: 'order.acceptorName',
  147. label: '受理人',
  148. width: 120,
  149. },
  150. { prop: 'order.orgLevelOneName', label: '一级部门', width: 150 },
  151. { prop: 'order.actualHandleOrgName', label: '接办部门', width: 150 },
  152. {
  153. label: '受理时间',
  154. prop: 'order.startTime',
  155. width: 170,
  156. render: (scope: any) => {
  157. return <span>{formatDate(scope.row.order?.startTime, 'YYYY-mm-dd HH:MM:SS')}</span>;
  158. },
  159. },
  160. {
  161. label: '办结时间',
  162. prop: 'order.filedTime',
  163. width: 170,
  164. render: (scope: any) => {
  165. return <span>{formatDate(scope.row.order?.filedTime, 'YYYY-mm-dd HH:MM:SS')}</span>;
  166. },
  167. },
  168. {
  169. label: '办结时间',
  170. prop: 'order.filedTime',
  171. width: 170,
  172. render: (scope: any) => {
  173. return <span>{formatDate(scope.row.order?.filedTime, 'YYYY-mm-dd HH:MM:SS')}</span>;
  174. },
  175. },
  176. {
  177. label: '发布时间',
  178. prop: 'publishTime',
  179. width: 170,
  180. render: (scope: any) => {
  181. return <span>{formatDate(scope.row?.publishTime, 'YYYY-mm-dd HH:MM:SS')}</span>;
  182. },
  183. },
  184. { prop: 'employeeName', label: '回访人', width: 170 },
  185. ]);
  186. const proTableRef = ref<RefType>();
  187. const canChoose = computed(() => {
  188. return proTableRef.value?.selectedList.length;
  189. });
  190. // 基础信息
  191. const getBaseData = async () => {
  192. const acceptTypeOptions = await smartVisitBaseData();
  193. state.acceptTypeOptions = acceptTypeOptions.result?.acceptTypeOptions;
  194. };
  195. // 打开弹窗
  196. const openDialog = () => {
  197. state.dialogVisible = true;
  198. getBaseData();
  199. queryList();
  200. };
  201. const close = () => {
  202. ruleFormRef.value?.clearValidate();
  203. ruleFormRef.value?.resetFields();
  204. };
  205. // 获取所有工单列表
  206. const queryList = async () => {
  207. state.loading = true;
  208. try {
  209. const res = await getSmartVisitRecord(state.queryParams);
  210. state.tableData = res.result;
  211. state.loading = false;
  212. } catch (e) {
  213. console.log(e);
  214. state.loading = false;
  215. }
  216. };
  217. // 重置所有工单列表
  218. const queryFormRef = ref<RefType>();
  219. const hotSpotRef = ref<RefType>();
  220. const resetQuery = (formEl: FormInstance | undefined) => {
  221. if (!formEl) return;
  222. formEl.resetFields();
  223. hotSpotRef.value?.reset();
  224. queryList();
  225. };
  226. // 确定选择所有工单到重复工单
  227. const ruleFormRef = ref<RefType>();
  228. const onSubmit = async (formEl: FormInstance | undefined) => {
  229. if (!formEl) return;
  230. await formEl.validate((valid: boolean) => {
  231. if (!valid) return;
  232. state.loading = true;
  233. const request = {
  234. name: state.ruleForm.name,
  235. beginTime: state.ruleForm.crTime[0],
  236. endTime: state.ruleForm.crTime[1],
  237. festivalBan: state.ruleForm.festivalBan,
  238. aiOrderVisitDetails: proTableRef.value?.selectedList.map((item: any) => {
  239. return {
  240. orderId: item.order?.id,
  241. orderVisitId: item.id,
  242. outerNo: item.order?.contact,
  243. };
  244. }),
  245. };
  246. smartVisitAdd(request)
  247. .then(() => {
  248. state.loading = false;
  249. state.dialogVisible = false;
  250. ElMessage.success('操作成功');
  251. emit('updateList');
  252. })
  253. .catch(() => {
  254. state.loading = false;
  255. });
  256. });
  257. };
  258. defineExpose({
  259. openDialog,
  260. });
  261. </script>