index.vue 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465
  1. <template>
  2. <div class="business-order-container layout-pd">
  3. <el-card shadow="never">
  4. <el-form :model="state.queryParams" ref="ruleFormRef" @submit.native.prevent label-width="100px">
  5. <el-row :gutter="10">
  6. <el-col :xs="24" :sm="12" :md="12" :lg="8" :xl="8">
  7. <el-form-item label="关键字" prop="Keyword">
  8. <el-input v-model="state.queryParams.Keyword" placeholder="工单编码/标题" clearable @keyup.enter="queryList" />
  9. </el-form-item>
  10. </el-col>
  11. <el-col :xs="24" :sm="12" :md="12" :lg="8" :xl="8">
  12. <el-form-item label="工单状态" prop="Status">
  13. <el-select
  14. v-model="state.queryParams.Status"
  15. placeholder="请选择工单状态"
  16. multiple
  17. clearable
  18. class="w100"
  19. collapse-tags
  20. collapse-tags-tooltip
  21. :max-collapse-tags="2"
  22. >
  23. <el-option v-for="item in state.orderStatusOptions" :value="item.key" :key="item.key" :label="item.value" />
  24. </el-select>
  25. </el-form-item>
  26. </el-col>
  27. <transition name="el-zoom-in-top">
  28. <el-col :xs="24" :sm="12" :md="12" :lg="8" :xl="8" v-show="!searchCol">
  29. <el-form-item label="受理类型" prop="AcceptType">
  30. <el-select
  31. v-model="state.queryParams.AcceptType"
  32. placeholder="请选择受理类型"
  33. multiple
  34. clearable
  35. class="w100"
  36. collapse-tags
  37. collapse-tags-tooltip
  38. :max-collapse-tags="2"
  39. >
  40. <el-option v-for="item in state.acceptTypeOptions" :value="item.dicDataValue" :key="item.dicDataValue" :label="item.dicDataName" />
  41. </el-select>
  42. </el-form-item>
  43. </el-col>
  44. </transition>
  45. <transition name="el-zoom-in-top">
  46. <el-col :xs="24" :sm="12" :md="12" :lg="8" :xl="8" v-show="!searchCol">
  47. <el-form-item label="来源渠道" prop="Channel">
  48. <el-select
  49. v-model="state.queryParams.Channel"
  50. placeholder="请选择来源渠道"
  51. multiple
  52. clearable
  53. class="w100"
  54. collapse-tags
  55. collapse-tags-tooltip
  56. :max-collapse-tags="2"
  57. >
  58. <el-option v-for="item in state.channelOptions" :value="item.dicDataValue" :key="item.dicDataValue" :label="item.dicDataName" />
  59. </el-select>
  60. </el-form-item>
  61. </el-col>
  62. </transition>
  63. <transition name="el-zoom-in-top">
  64. <el-col :xs="24" :sm="12" :md="12" :lg="8" :xl="8" v-show="!searchCol">
  65. <el-form-item label="热点分类" prop="HotspotId">
  66. <hot-spot-select
  67. v-model="state.queryParams.hotspotId"
  68. class="w100"
  69. :hotspotExternal="state.hotspotExternal"
  70. show-checkbox
  71. ref="hotSpotRef"
  72. />
  73. </el-form-item>
  74. </el-col>
  75. </transition>
  76. <transition name="el-zoom-in-top">
  77. <el-col :xs="24" :sm="12" :md="12" :lg="8" :xl="8" v-show="!searchCol">
  78. <el-form-item label="部门" prop="OrgCode">
  79. <el-cascader
  80. :options="state.orgsOptions"
  81. filterable
  82. :show-all-levels="false"
  83. :props="{ checkStrictly: true, value: 'id', label: 'name', emitPath: false, multiple: true }"
  84. placeholder="请选择所属部门"
  85. clearable
  86. class="w100"
  87. v-model="state.queryParams.OrgCode"
  88. ref="cascadeRef"
  89. @change="getKnowledgeList"
  90. collapse-tags
  91. collapse-tags-tooltip
  92. :max-collapse-tags="2"
  93. >
  94. </el-cascader>
  95. </el-form-item>
  96. </el-col>
  97. </transition>
  98. <transition name="el-zoom-in-top">
  99. <el-col :xs="24" :sm="12" :md="12" :lg="8" :xl="8" v-show="!searchCol">
  100. <el-form-item label="受理坐席" prop="NameOrNo">
  101. <el-input v-model="state.queryParams.NameOrNo" placeholder="坐席姓名/坐席工号" clearable @keyup.enter="queryList" />
  102. </el-form-item>
  103. </el-col>
  104. </transition>
  105. <transition name="el-zoom-in-top">
  106. <el-col :xs="24" :sm="12" :md="12" :lg="8" :xl="8" v-show="!searchCol">
  107. <el-form-item label="受理时间" prop="crTime">
  108. <el-date-picker
  109. v-model="state.queryParams.crTime"
  110. type="datetimerange"
  111. unlink-panels
  112. range-separator="至"
  113. start-placeholder="开始时间"
  114. end-placeholder="结束时间"
  115. :shortcuts="shortcuts"
  116. @change="timeStartChangeCr"
  117. value-format="YYYY-MM-DD[T]HH:mm:ss"
  118. />
  119. </el-form-item>
  120. </el-col>
  121. </transition>
  122. <el-col :xs="24" :sm="12" :md="12" :lg="8" :xl="8">
  123. <el-form-item label=" ">
  124. <div class="flex-end w100">
  125. <el-button type="primary" @click="queryList" :loading="state.loading"> <SvgIcon name="ele-Search" class="mr5" />查询 </el-button>
  126. <el-button @click="resetQuery(ruleFormRef)" v-waves class="default-button" :loading="state.loading">
  127. <SvgIcon name="ele-Refresh" class="mr5" />重置
  128. </el-button>
  129. <el-button link type="primary" @click="closeSearch" :loading="state.loading">
  130. {{ searchCol ? '展开' : '收起' }}
  131. <SvgIcon :class="{ 'is-reverse': searchCol }" name="ele-ArrowUp" class="mr5 arrow" size="18px" />
  132. </el-button>
  133. </div>
  134. </el-form-item>
  135. </el-col>
  136. </el-row>
  137. </el-form>
  138. </el-card>
  139. <el-card shadow="never">
  140. <!-- 功能按钮 -->
  141. <div class="mb20">
  142. <el-button type="primary" @click="onCreateRepeatEvent"> <SvgIcon name="ele-Plus" class="mr5" /> 创建重复性事件 </el-button>
  143. <el-button type="primary" @click="onObserve" v-auth="'business:order:observe'" :disabled="!multipleSelection.length">
  144. <SvgIcon name="ele-View" class="mr5" />设置观察件
  145. </el-button>
  146. <el-button type="primary" @click="onEnd" v-auth="'business:order:end'" :disabled="!multipleSelection.length">
  147. <SvgIcon name="ele-Stopwatch" class="mr5" />设置终结件
  148. </el-button>
  149. </div>
  150. <!-- 表格 -->
  151. <el-table
  152. :data="state.tableData"
  153. v-loading="state.loading"
  154. row-key="id"
  155. @sort-change="sortChange"
  156. ref="multipleTableRef"
  157. @selection-change="handleSelectionChange"
  158. >
  159. <el-table-column type="selection" width="55" />
  160. <el-table-column label="超期状态" width="80" align="center">
  161. <template #default="{ row }">
  162. <span :class="'overdue-status-'+row.expiredStatus" :title="row.expiredStatusText"></span>
  163. </template>
  164. </el-table-column>
  165. <el-table-column prop="no" label="工单编码" show-overflow-tooltip width="150"></el-table-column>
  166. <el-table-column width="100" label="省/市工单" prop="isProvince">
  167. <template #default="{ row }">
  168. <span>{{ row.isProvince ? '省工单' : '市工单' }}</span>
  169. </template>
  170. </el-table-column>
  171. <el-table-column prop="currentStepName" label="办理节点" show-overflow-tooltip width="150"></el-table-column>
  172. <el-table-column label="工单状态" show-overflow-tooltip width="100" prop="statusText"></el-table-column>
  173. <el-table-column label="标题" show-overflow-tooltip width="300">
  174. <template #default="{ row }">
  175. <span class="color-primary">{{ row.title }}</span>
  176. </template>
  177. </el-table-column>
  178. <el-table-column label="受理时间" show-overflow-tooltip width="170">
  179. <template #default="{ row }">
  180. <span>{{ formatDate(row.startTime, 'YYYY-mm-dd HH:MM:SS') }}</span>
  181. </template>
  182. </el-table-column>
  183. <!-- <el-table-column prop="" label="延期申请" show-overflow-tooltip width="150"></el-table-column>
  184. <el-table-column prop="" label="甄别状态" show-overflow-tooltip width="150"></el-table-column>-->
  185. <el-table-column prop="expiredTime" label="工单期满时间" show-overflow-tooltip width="170">
  186. <template #default="{ row }">
  187. <span>{{ formatDate(row.expiredTime, 'YYYY-mm-dd HH:MM:SS') }}</span>
  188. </template>
  189. </el-table-column>
  190. <el-table-column label="办结时间" show-overflow-tooltip width="170">
  191. <template #default="{ row }">
  192. <span>{{ formatDate(row.filedTime, 'YYYY-mm-dd HH:MM:SS') }}</span>
  193. </template>
  194. </el-table-column>
  195. <el-table-column prop="orgLevelOneName" label="一级部门" show-overflow-tooltip width="170"></el-table-column>
  196. <el-table-column prop="actualHandleOrgName" label="接办部门" show-overflow-tooltip width="170"></el-table-column>
  197. <el-table-column prop="acceptType" label="受理类型" show-overflow-tooltip width="150"></el-table-column>
  198. <el-table-column prop="counterSignTypeText" label="中心会签" show-overflow-tooltip width="100"></el-table-column>
  199. <el-table-column prop="sourceChannel" label="来源方式" show-overflow-tooltip width="100"></el-table-column>
  200. <el-table-column prop="hotspotName" label="热点分类" show-overflow-tooltip width="200"></el-table-column>
  201. <el-table-column prop="tagNames" label="工单标签" show-overflow-tooltip width="200"></el-table-column>
  202. <el-table-column prop="employeeName" label="受理人" show-overflow-tooltip width="120">
  203. <template #default="{ row }">
  204. <span
  205. >{{ row.acceptorName }} <span v-if="row.acceptorStaffNo">[{{ row.acceptorStaffNo }}]</span>
  206. </span>
  207. </template>
  208. </el-table-column>
  209. <el-table-column label="操作" width="140" fixed="right" align="center">
  210. <template #default="{ row }">
  211. <el-button link type="success" @click="onOrderEdit(row)" title="编辑工单" v-if="row.canEdit" v-auth="'business:order:edit'">
  212. 修改
  213. </el-button>
  214. <order-detail :order="row" @updateList="queryList" v-if="row.workflowId"/>
  215. </template>
  216. </el-table-column>
  217. <template #empty>
  218. <Empty />
  219. </template>
  220. </el-table>
  221. <!-- 分页 -->
  222. <pagination
  223. :total="state.total"
  224. v-model:page="state.queryParams.PageIndex"
  225. v-model:limit="state.queryParams.PageSize"
  226. @pagination="queryList"
  227. />
  228. </el-card>
  229. <!-- 编辑重复性事件 -->
  230. <repeat-event-edit ref="repeatEventEditRef" @updateList="queryList" />
  231. </div>
  232. </template>
  233. <script setup lang="ts" name="order">
  234. import { defineAsyncComponent, onMounted, reactive, ref } from 'vue';
  235. import type { FormInstance } from 'element-plus';
  236. import { ElButton, ElMessage, ElMessageBox } from 'element-plus';
  237. import { throttle } from '@/utils/tools';
  238. import { shortcuts } from '@/utils/constants';
  239. import { auth } from '@/utils/authFunction';
  240. import other from '@/utils/other';
  241. import { useRoute, useRouter } from 'vue-router';
  242. import { formatDate } from '@/utils/formatTime';
  243. import { hotSpotType, listBaseData, orderList } from '@/api/business/order';
  244. import { addObserve } from '@/api/query/observe';
  245. import { addEnd } from '@/api/query/end';
  246. // 引入组件
  247. const OrderDetail = defineAsyncComponent(() => import('@/components/OrderDetail/index.vue')); // 工单详情
  248. const RepeatEventEdit = defineAsyncComponent(() => import('@/views/business/repeatEvent/components/Repeat-event-edit.vue')); // 编辑重复性事件
  249. const HotSpotSelect = defineAsyncComponent(() => import('@/components/Hotspot/index.vue')); // 选择热点
  250. // 定义变量内容
  251. const state = reactive(<any>{
  252. queryParams: {
  253. // 查询条件
  254. PageIndex: 1, // 当前页
  255. PageSize: 10, // 每页条数
  256. Keyword: null, // 关键字
  257. Content: null, // 工单内容
  258. AcceptType: null, // 受理类型
  259. Channel: null, // 渠道
  260. HotspotId: [], // 热点
  261. OrgCode: [], // 机构
  262. NameOrNo: null, // 受理坐席
  263. crTime: [], // 创建时间
  264. CreationTimeStart: null, // 创建时间 开始
  265. CreationTimeEnd: null, // 创建时间 结束
  266. TransferPhone: null, // 转派人
  267. EmergencyLevel: [], // 紧急程度
  268. exTime: [], // 办理期限
  269. ExpiredTimeStart: null, //办理期限 开始
  270. ExpiredTimeEnd: null, //办理期限 结束
  271. PhoneNo: null, // 手机号
  272. Status: [], // 状态
  273. pushTypeOptions: null, //
  274. PushTypeCode: null, //推送类型
  275. },
  276. tableData: [], //表单
  277. loading: false, // 加载
  278. total: 0, // 总数
  279. acceptTypeOptions: [], //受理类型
  280. channelOptions: [], // 来源频道
  281. emergencyLevelOptions: [], // 紧急程度
  282. orderStatusOptions: [], // 工单状态
  283. orgsOptions: [], // 部门
  284. pushTypeOptions: [], //推送分类
  285. orgData: [], // 机构数据
  286. });
  287. const ruleFormRef = ref<RefType>(); // 表单ref
  288. const searchCol = ref(true); // 展开/收起
  289. const route = useRoute(); // 路由
  290. const router = useRouter(); // 路由
  291. // 热点分类远程搜索
  292. const HotspotProps = {
  293. label: 'hotSpotName',
  294. children: 'children',
  295. isLeaf: 'isLeaf',
  296. };
  297. // 热点分类远程搜索
  298. const load = async (node: any, resolve: any) => {
  299. if (node.isLeaf) return resolve([]);
  300. let res: any = await hotSpotType({ id: node.data.id ? node.data.id : '' });
  301. resolve(res.result);
  302. };
  303. // 获取选择组织name值
  304. const cascadeRef = ref<RefType>();
  305. const getKnowledgeList = () => {
  306. let currentNode = cascadeRef.value.getCheckedNodes();
  307. state.queryParams.orgCode = currentNode[0]?.data.orgCode ?? '';
  308. };
  309. // 展开/收起
  310. const closeSearch = () => {
  311. searchCol.value = !searchCol.value;
  312. };
  313. const handleTimeChange = (val: string[], startKey: string, endKey: string) => {
  314. if (val) {
  315. state.queryParams[startKey] = val[0];
  316. state.queryParams[endKey] = val[1];
  317. } else {
  318. state.queryParams[startKey] = '';
  319. state.queryParams[endKey] = '';
  320. }
  321. };
  322. // 受理时间
  323. const timeStartChangeCr = (val: string[]) => {
  324. handleTimeChange(val, 'CreationTimeStart', 'CreationTimeEnd');
  325. };
  326. // 获取查询条件基础信息
  327. const getBaseData = async () => {
  328. const res: any = await listBaseData();
  329. const mappings: any = {
  330. acceptTypeOptions: 'acceptTypeOptions',
  331. channelOptions: 'channelOptions',
  332. emergencyLevelOptions: 'emergencyLevelOptions',
  333. orgsOptions: 'orgsOptions',
  334. pushTypeOptions: 'pushTypeOptions',
  335. orderStatusOptions: 'orderStatusOptions',
  336. };
  337. for (const key in mappings) {
  338. state[key] = res.result?.[mappings[key]] ?? [];
  339. }
  340. };
  341. /** 获取列表 */
  342. const queryList = () => {
  343. if (!auth('business:order:query')) ElMessage.error('抱歉,您没有权限查看工单列表!');
  344. else {
  345. let request = other.deepClone(state.queryParams);
  346. Reflect.deleteProperty(request, 'crTime'); // 删除无用的参数
  347. Reflect.deleteProperty(request, 'exTime'); // 删除无用的参数
  348. state.loading = true;
  349. orderList(request)
  350. .then((response: any) => {
  351. state.tableData = response?.result.items ?? [];
  352. state.total = response?.result.total;
  353. state.loading = false;
  354. })
  355. .catch(() => {
  356. state.loading = false;
  357. });
  358. }
  359. };
  360. // 表格排序
  361. const sortChange = (column: any) => {
  362. console.log(column);
  363. };
  364. const hotSpotRef = ref<RefType>();
  365. /** 重置按钮操作 */
  366. const resetQuery = throttle((formEl: FormInstance | undefined) => {
  367. if (!formEl) return;
  368. formEl.resetFields();
  369. state.queryParams.CreationTimeStart = null;
  370. state.queryParams.CreationTimeEnd = null;
  371. state.queryParams.ExpiredTimeStart = null;
  372. state.queryParams.ExpiredTimeStart = null;
  373. hotSpotRef.value.reset();
  374. queryList();
  375. }, 300);
  376. // 表格多选
  377. const multipleTableRef = ref<RefType>();
  378. const multipleSelection = ref<any>([]);
  379. const handleSelectionChange = (val: any[]) => {
  380. multipleSelection.value = val;
  381. };
  382. // 导出
  383. const onExport = () => {
  384. console.log('导出');
  385. };
  386. // 设置终结件
  387. const onObserve = () => {
  388. const titles = multipleSelection.value.map((item: any) => item.title).join(',');
  389. const ids = multipleSelection.value.map((item: any) => {
  390. return {
  391. orderId: item.id,
  392. };
  393. });
  394. ElMessageBox.confirm(`确定要将【${titles}】设置观察件吗?`, '提示', {
  395. confirmButtonText: '确定',
  396. cancelButtonText: '取消',
  397. type: 'warning',
  398. draggable: true,
  399. autofocus: false,
  400. })
  401. .then(() => {
  402. addObserve({ orderIds: ids }).then(() => {
  403. ElMessage.success('操作成功');
  404. queryList();
  405. });
  406. })
  407. .catch(() => {});
  408. };
  409. // 设置终结件
  410. const onEnd = () => {
  411. const titles = multipleSelection.value.map((item: any) => item.title).join(',');
  412. const ids = multipleSelection.value.map((item: any) => {
  413. return {
  414. orderId: item.id,
  415. };
  416. });
  417. ElMessageBox.confirm(`确定要将【${titles}】设置终结件吗?`, '提示', {
  418. confirmButtonText: '确定',
  419. cancelButtonText: '取消',
  420. type: 'warning',
  421. draggable: true,
  422. autofocus: false,
  423. })
  424. .then(() => {
  425. addEnd({ orderIds: ids }).then(() => {
  426. ElMessage.success('操作成功');
  427. queryList();
  428. });
  429. })
  430. .catch(() => {});
  431. };
  432. // 创建重复性事件
  433. const repeatEventEditRef = ref<RefType>();
  434. const onCreateRepeatEvent = () => {
  435. repeatEventEditRef.value.openDialog();
  436. };
  437. // 编辑工单
  438. const onOrderEdit = (row: any) => {
  439. router.push({
  440. name: 'orderAccept',
  441. params: {
  442. tagsViewName: '工单受理-' + row.no,
  443. id: row.id,
  444. callId: '0',
  445. },
  446. });
  447. };
  448. onMounted(() => {
  449. getBaseData();
  450. queryList();
  451. });
  452. </script>
  453. <style scoped lang="scss">
  454. .business-order-container {
  455. .arrow {
  456. transition: transform var(--el-transition-duration);
  457. cursor: pointer;
  458. }
  459. .arrow.is-reverse {
  460. transform: rotateZ(-180deg);
  461. }
  462. }
  463. </style>