index.vue 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547
  1. <template>
  2. <div class="h-full flex">
  3. <div class="p-5 w-80 pr-0" v-if="layoutSingleChoice == TABLE_VIEW">
  4. <div class="bg-white w-full h-full shadow-md rounded-md flex flex-col">
  5. <div class="flex-1 p-3 overflow-y-auto scroll-bar">
  6. <el-form :model="searchForm">
  7. <el-form-item label="任务名称:" label-width="7em" prop="taskName">
  8. <el-input v-model="searchForm.taskName" placeholder="请输入" />
  9. </el-form-item>
  10. <el-form-item label="优先级:" label-width="7em" prop="priority" v-if="userInfo.company.isSimple != 1">
  11. <el-select v-model="searchForm.priority" placeholder="请选择">
  12. <el-option v-for="item in PRIORITY" :key="item.value" :value="item.value" :label="item.label" />
  13. </el-select>
  14. </el-form-item>
  15. <el-form-item label="客户名称:" label-width="7em" prop="customName">
  16. <el-input v-model="searchForm.customName" placeholder="请输入" />
  17. </el-form-item>
  18. <el-form-item label="联系人号码:" label-width="7em" prop="contactsName">
  19. <el-input v-model="searchForm.contactsName" placeholder="请输入" />
  20. </el-form-item>
  21. <el-form-item label="执行人:" label-width="7em" prop="executorName">
  22. <el-input v-model="searchForm.executorName" placeholder="请输入" />
  23. </el-form-item>
  24. <el-form-item :label="`${businessLabel}名称`" label-width="7em" prop="businessName">
  25. <el-input v-model="searchForm.businessName" placeholder="请输入" />
  26. </el-form-item>
  27. <el-form-item label="销售订单:" label-width="7em" prop="orderName">
  28. <el-input v-model="searchForm.orderName" placeholder="请输入" />
  29. </el-form-item>
  30. <el-form-item label="线索名称:" label-width="7em" prop="clueName" v-if="userInfo.company.isSimple != 1">
  31. <el-input v-model="searchForm.clueName" placeholder="请输入" />
  32. </el-form-item>
  33. <el-form-item label="任务状态:" label-width="7em" prop="status">
  34. <el-select v-model="searchForm.status" placeholder="请选择">
  35. <el-option v-for="item in STATUS" :key="item.value" :value="item.value" :label="item.label" />
  36. </el-select>
  37. </el-form-item>
  38. <el-form-item label="开始时间:" label-width="7em" prop="startDate">
  39. <el-date-picker v-model="searchForm.startDate" type="date" placeholder="选择日期" value-format="YYYY-MM-DD" />
  40. </el-form-item>
  41. <el-form-item label="截止时间:" label-width="7em" prop="endDate">
  42. <el-date-picker v-model="searchForm.endDate" type="date" placeholder="选择日期" value-format="YYYY-MM-DD" />
  43. </el-form-item>
  44. </el-form>
  45. </div>
  46. <div class="w-full flex p-3 shadow-[0_-3px_5px_0px_rgba(0,0,0,0.2)]">
  47. <el-button size="large" class="w-full" @click="reset()">重置</el-Button>
  48. <el-button type="primary" size="large" class="w-full" @click="search()">搜索</el-Button>
  49. </div>
  50. </div>
  51. </div>
  52. <div class="flex-1 p-5 overflow-auto">
  53. <div class="bg-white w-full h-full p-3 shadow-md rounded-md flex flex-col">
  54. <div class="p-3">
  55. <div class="flex items-center w-full justify-between">
  56. <div>
  57. <el-radio-group v-model="layoutSingleChoice" @change="viewsSwitching">
  58. <el-radio-button label="表格视图" :value="TABLE_VIEW" />
  59. <el-radio-button label="日历视图" :value="KANBAN_VIEW" />
  60. </el-radio-group>
  61. </div>
  62. <div class="justify-end flex">
  63. <el-button type="primary" v-permission="['tasksAdd']" @click="createTasks()">创建任务</el-Button>
  64. <el-button type="primary" v-permission="['tasksDelete']" :disabled="len == 0" :loading="btnLoading" @click="deleteTasks()">批量删除</el-Button>
  65. <el-button type="primary" v-permission="['tasksImport']" @click="openImportModal()">导入</el-Button>
  66. <!-- <el-button type="primary" :loading="btnLoading" @click="exportTasks()">导出</el-Button> -->
  67. <el-button type="primary" v-permission="['tasksExport']" :loading="btnLoading" @click="newExportTasks()">导出</el-Button>
  68. </div>
  69. </div>
  70. </div>
  71. <template v-if="layoutSingleChoice == TABLE_VIEW">
  72. <div class="flex-1 overflow-y-auto">
  73. <el-table :data="tableData" :show-overflow-tooltip="tableShowOverflowTooltip" style="width: 100%;height: 100%;" ref="tableRef" v-loading="loading">
  74. <el-table-column type="selection" width="55" />
  75. <el-table-column prop="taskName" label="任务名称" header-align="center" align="center" show-overflow-tooltip
  76. width="200" />
  77. <el-table-column prop="priority" label="优先级" width="100" :sortable="true" header-align="center"
  78. align="center" v-if="userInfo.company.isSimple != 1">
  79. <template #default="scope">
  80. {{ PRIORITY.find(item => item.value == scope.row.priority)?.label }}
  81. </template>
  82. </el-table-column>
  83. <el-table-column prop="status" label="状态" width="100" header-align="center" align="center">
  84. <template #default="scope">
  85. <el-text :type="STATUS[scope.row.status]?.type">
  86. {{ STATUS[scope.row.status]?.label }}
  87. </el-text>
  88. </template>
  89. </el-table-column>
  90. <el-table-column prop="executorNames" label="执行人" width="120" header-align="center" align="center">
  91. <template #default="scope">
  92. <template v-for="(item, index) in (scope.row.taskExecutors || [])">
  93. <TextTranslation translationTypes="userName" :translationValue="item">
  94. </TextTranslation>
  95. <span v-if="index < (scope.row.taskExecutors || []).length - 1">,</span>
  96. </template>
  97. </template>
  98. </el-table-column>
  99. <el-table-column prop="startDate" label="开始时间" width="200" :sortable="true" header-align="center"
  100. align="center" value-format="YYYY-MM-DD" />
  101. <el-table-column prop="endDate" label="截止时间" width="200" :sortable="true" header-align="center"
  102. align="center" value-format="YYYY-MM-DD">
  103. <template #default="scope">
  104. <div :class="`${scope.row.endDate && scope.row.endDate < dateOfTheDay ? 'text-[#F56C6C]' : '' }`">{{ scope.row.endDate }}</div>
  105. </template>
  106. </el-table-column>
  107. <el-table-column prop="customName" label="客户名称" header-align="center" align="center" width="120">
  108. <template #default="scope">
  109. <el-link :underline="false" type="primary" @click="goDetail(scope.row, 'customer', 'customId')">
  110. {{ scope.row.customName }}
  111. </el-link>
  112. </template>
  113. </el-table-column>
  114. <el-table-column prop="businessName" :label="`${businessLabel}名称`" header-align="center" align="center" width="200" v-if="userInfo.company.isSimple != 1">
  115. <template #default="scope">
  116. <el-link :underline="false" type="primary"
  117. @click="goDetail(scope.row, 'business', 'businessOpportunityId')">
  118. {{ scope.row.businessName }}
  119. </el-link>
  120. </template>
  121. </el-table-column>
  122. <el-table-column prop="orderName" label="销售订单" header-align="center" align="center" width="200" v-if="userInfo.company.isSimple != 1">
  123. <template #default="scope">
  124. <el-link :underline="false" type="primary" @click="goDetail(scope.row, 'order', 'orderId')">
  125. {{ scope.row.orderName }}
  126. </el-link>
  127. </template>
  128. </el-table-column>
  129. <el-table-column prop="clueName" label="线索名称" header-align="center" align="center" width="200" v-if="userInfo.company.isSimple != 1">
  130. <template #default="scope">
  131. <el-link :underline="false" type="primary" @click="goDetail(scope.row, 'thread', 'clueId')">
  132. {{ scope.row.clueName }}
  133. </el-link>
  134. </template>
  135. </el-table-column>
  136. <el-table-column prop="contactsName" label="联系人名称" header-align="center" align="center" width="120" v-if="userInfo.company.isSimple != 1">
  137. <template #default="scope">
  138. <el-link :underline="false" type="primary" @click="goDetail(scope.row, 'contacts', 'contactsId')">
  139. {{ scope.row.contactsName }}
  140. </el-link>
  141. </template>
  142. </el-table-column>
  143. <template v-if="userInfo.company.isSimple == 1">
  144. <el-table-column prop="contactsTel" label="联系人号码" header-align="center" align="center" width="140" />
  145. <el-table-column prop="appointContent" label="预约工作内容" header-align="center" align="center" width="140" />
  146. <el-table-column prop="appointMoney" label="预约金额" header-align="center" align="center" width="140" />
  147. <el-table-column prop="reallyContent" label="实际工作内容" header-align="center" align="center" width="140" />
  148. <el-table-column prop="reallyMoney" label="实际金额" header-align="center" align="center" width="140" />
  149. <el-table-column prop="payType" label="付款状态" header-align="center" align="center" width="140">
  150. <template #default="scope">
  151. <el-text :type="scope.row.payType == 1 ? 'success' : 'danger'">
  152. {{ scope.row.payType == 1 ? '已付款' : '未付款' }}
  153. </el-text>
  154. </template>
  155. </el-table-column>
  156. <el-table-column prop="userBack" label="用户反馈" header-align="center" align="center" width="180" />
  157. </template>
  158. <el-table-column fixed="right" label="操作" header-align="center" align="center" width="160" v-permission="['tasksEdit']">
  159. <template #default="scope">
  160. <el-button link type="primary" @click.prevent="editRow(scope.row)">
  161. 编辑
  162. </el-button>
  163. <el-button link type="primary" v-if="scope.row.status == '2'"
  164. @click.prevent="restart(scope.row)">
  165. 重启
  166. </el-button>
  167. <el-button link type="primary" v-else @click.prevent="finishRow(scope.row)">
  168. 完成
  169. </el-button>
  170. <el-button link type="danger" v-permission="['tasksDelete']" @click.prevent="deleteRow(scope.row)">
  171. 删除
  172. </el-button>
  173. </template>
  174. </el-table-column>
  175. </el-table>
  176. </div>
  177. <div class="ml-auto">
  178. <el-pagination layout="total, prev, pager, next, sizes" :total="totalCount"
  179. :current-page="searchForm.pageIndex" @size-change="sizeChage" @current-change="currentChange" />
  180. </div>
  181. </template>
  182. <template v-if="layoutSingleChoice == KANBAN_VIEW">
  183. <div class="w-full p-4 h-full overflow-auto scroll-bar">
  184. <taskCalendar ref="taskCalendarRef" />
  185. </div>
  186. </template>
  187. </div>
  188. </div>
  189. <el-dialog v-model="restartPopUpWindowVisable" title="重启任务" width="500">
  190. <div class="mt-8">
  191. <el-form :model="restartFrom">
  192. <el-form-item label="重启时间" label-width="7em" prop="showStartDelayData">
  193. <el-date-picker
  194. v-model="restartFrom.timesList"
  195. type="datetimerange"
  196. start-placeholder="开始时间"
  197. end-placeholder="结束时间"
  198. value-format="YYYY-MM-DD HH:mm"
  199. format="YYYY-MM-DD HH:mm"
  200. style="width: 300px"
  201. :disabled-minutes="disableMinute"
  202. />
  203. </el-form-item>
  204. <div class="text-[#ff4e4e] ml-8">重启任务的时间不能在今天之前</div>
  205. </el-form>
  206. </div>
  207. <template #footer>
  208. <div class="dialog-footer">
  209. <el-button @click="restartPopUpWindowVisable = false">取消</el-button>
  210. <el-button type="primary" @click="restartTaksTime">
  211. 确定
  212. </el-button>
  213. </div>
  214. </template>
  215. </el-dialog>
  216. <TaskModal :visible="taskModalVisible" :title="isEdit ? '编辑任务' : '新建任务'" :save-loading="taskLoading"
  217. :edit-form="taskForm" :show-log="isEdit" @close="closeTaskModal" @submit="submitForm" />
  218. <ImportModal :visible="importVisible" :save-loading="importLoading" @close="closeImportModal"
  219. @submit="importExcel" />
  220. <ExportModal :visible="exportVisible" :save-loading="exportLoading" @close="closeExportModal"
  221. @submit="exportExcel" />
  222. </div>
  223. </template>
  224. <script lang="ts" setup>
  225. import { computed, inject, onBeforeMount, onMounted, ref, } from 'vue';
  226. import { useRouter } from 'vue-router';
  227. import { useStore } from '@/store';
  228. import { MOD, PRIORITY, STATUS, defaultSearchForm, PAGE_LIST, ADD_TASK, DELETE_TASKS, UPDATE_TASK, UPDATE_TASK_STATUS, IMPORT_DATA, EXPORT_DATA, EXPORT_DATA_BY_TASK_ID, TABLE_VIEW, KANBAN_VIEW } from './api';
  229. import { ElTable, dayjs } from 'element-plus';
  230. import TaskModal from '@/components/TaskModal/index.vue';
  231. import ImportModal from './ImportModal.vue';
  232. import ExportModal from './ExportModal.vue';
  233. import taskCalendar from './taskCalendar.vue';
  234. import { post, uploadFile } from '@/utils/request';
  235. import { getFromValue, confirmAction, downloadFile, createTaskFromType } from '@/utils/tools';
  236. import { tableShowOverflowTooltip } from '@/utils/globalVariables'
  237. import { pushMap } from './type';
  238. const router = useRouter()
  239. const { getFunctionList, userInfo } = useStore()
  240. const globalPopup = inject<GlobalPopup>('globalPopup')
  241. const pagePermission = ref<any[]>();
  242. const taskModalVisible = ref(false);
  243. const taskForm = ref<any>();
  244. const taskModalVisibleKey = ref<number>(1)
  245. const isEdit = ref(false);
  246. const len = computed(() => {
  247. return tableRef.value?.getSelectionRows().length
  248. })
  249. const taskLoading = ref<saveLoadingType>("1");
  250. const restartPopUpWindowVisable = ref(false);
  251. const restartFrom = ref<any>({});
  252. const dateOfTheDay = ref<any>(dayjs().format('YYYY-MM-DD'))
  253. const isExistBusiness = sessionStorage.getItem("isExistBusiness");
  254. const businessLabel = isExistBusiness === "1" ? "商机" : "项目";
  255. const layoutSingleChoice = ref(TABLE_VIEW) // 表格视图
  256. // const layoutSingleChoice = ref(KANBAN_VIEW) // 日历视图
  257. const taskCalendarRef = ref<InstanceType<typeof taskCalendar> | null>()
  258. function viewsSwitching() {
  259. }
  260. function disableMinute() {
  261. // 只允许选择 00 和 30 分钟
  262. const allowed = [0, 30];
  263. const disabled = [];
  264. for (let i = 0; i < 60; i++) {
  265. if (!allowed.includes(i)) {
  266. disabled.push(i);
  267. }
  268. }
  269. // return disabled;
  270. return disabled;
  271. }
  272. function closeTaskModal() {
  273. taskModalVisible.value = false;
  274. taskForm.value = null;
  275. }
  276. function submitForm(data: any, isClose: boolean) {
  277. const { executorId, startDate, endDate, repeatEndDate } = data;
  278. let params = {
  279. ...data,
  280. startDate: startDate && dayjs(startDate).format('YYYY-MM-DD HH:mm'),
  281. endDate: endDate && dayjs(endDate).format('YYYY-MM-DD HH:mm'),
  282. repeatEndDate: repeatEndDate && dayjs(repeatEndDate).format('YYYY-MM-DD')
  283. }
  284. if (executorId) {
  285. params = {
  286. ...params,
  287. executorId: executorId.join(','),
  288. taskLogs: []
  289. }
  290. }
  291. delete params.taskLogs
  292. delete params.taskExecutors
  293. taskLoading.value = "2";
  294. let url = isEdit.value ? UPDATE_TASK : ADD_TASK
  295. let msg = isEdit.value ? "修改成功" : "新建成功"
  296. post(url, getFromValue(params)).then(() => {
  297. taskLoading.value = "3";
  298. taskModalVisible.value = isClose;
  299. globalPopup?.showSuccess(msg)
  300. search();
  301. }).catch(err => {
  302. taskLoading.value = "4"
  303. globalPopup?.showError(err.msg)
  304. })
  305. }
  306. const searchForm = ref<any>();
  307. const tableRef = ref<InstanceType<typeof ElTable>>();
  308. const loading = ref<boolean>(false);
  309. const totalCount = ref<number>(0);
  310. const tableData = ref<any[]>([])
  311. function newExportTasks() {
  312. btnLoading.value = true
  313. const { startDate, endDate } = searchForm.value;
  314. let params = {
  315. ...searchForm.value,
  316. startDate: startDate && dayjs(startDate).format('YYYY-MM-DD 00:00:00'),
  317. endDate: endDate && dayjs(endDate).format('YYYY-MM-DD 23:59:59')
  318. }
  319. post(EXPORT_DATA, {...getFromValue(params)}).then((res) => {
  320. globalPopup?.showSuccess("导出成功")
  321. downloadFile(res.data, "任务列表.xlsx");
  322. }).finally(() => {
  323. btnLoading.value = false
  324. })
  325. }
  326. function search() {
  327. loading.value = true;
  328. const { startDate, endDate } = searchForm.value;
  329. let params = {
  330. ...searchForm.value,
  331. startDate: startDate && dayjs(startDate).format('YYYY-MM-DD 00:00'),
  332. endDate: endDate && dayjs(endDate).format('YYYY-MM-DD 23:59')
  333. }
  334. post(PAGE_LIST, getFromValue(params)).then(({ data }) => {
  335. loading.value = false;
  336. const { total, record } = data;
  337. totalCount.value = total;
  338. tableData.value = record.map((item: any) => ({
  339. ...item,
  340. executorNames: item.taskExecutors?.join(',') ?? ''
  341. }));
  342. }).catch(err => {
  343. globalPopup?.showError(err.msg);
  344. loading.value = false;
  345. })
  346. }
  347. function reset() {
  348. searchForm.value = { ...defaultSearchForm };
  349. }
  350. function sizeChage(currentSize: number): void {
  351. searchForm.value = {
  352. ...searchForm.value,
  353. pageSize: currentSize,
  354. pageIndex: 1
  355. }
  356. search()
  357. }
  358. function currentChange(currentPage: number): void {
  359. searchForm.value = {
  360. ...searchForm.value,
  361. pageIndex: currentPage
  362. }
  363. search()
  364. }
  365. function createTasks() {
  366. taskModalVisible.value = true;
  367. // taskForm.value = null;
  368. taskForm.value = createTaskFromType(0);
  369. isEdit.value = false;
  370. }
  371. function deleteTasks() {
  372. confirmAction("确定删除所选内容吗?").then(() => {
  373. const taskIds = tableRef.value?.getSelectionRows()?.map((item: any) => item.id).join(",")
  374. post(DELETE_TASKS, {
  375. taskIds
  376. }).then(() => {
  377. search();
  378. globalPopup?.showSuccess("删除成功")
  379. }).catch(err => {
  380. globalPopup?.showError(err.msg)
  381. })
  382. });
  383. }
  384. const importVisible = ref(false);
  385. const importLoading = ref<saveLoadingType>("1");
  386. function openImportModal() {
  387. importVisible.value = true;
  388. }
  389. function closeImportModal() {
  390. importVisible.value = false;
  391. }
  392. function importExcel(data: any) {
  393. const formData = new FormData();
  394. formData.append("multipartFile", data);
  395. importLoading.value = "2";
  396. uploadFile(IMPORT_DATA, formData).then(_res => {
  397. globalPopup?.showSuccess("导入成功")
  398. importLoading.value = "3";
  399. if(layoutSingleChoice.value == TABLE_VIEW) {
  400. search();
  401. } else {
  402. taskCalendarRef.value && taskCalendarRef.value.getTaskCalendar()
  403. }
  404. }).catch(err => {
  405. globalPopup?.showError(err.msg)
  406. importLoading.value = "4";
  407. })
  408. }
  409. const exportVisible = ref(false);
  410. const exportLoading = ref<saveLoadingType>("1");
  411. const btnLoading = ref(false);
  412. function exportTasks() {
  413. const data: any[] = tableRef.value?.getSelectionRows()
  414. if (data.length === 0) {
  415. // TODO
  416. exportVisible.value = true;
  417. return
  418. }
  419. btnLoading.value = true;
  420. const taskIds = data.map((v: any) => v.id).join(",");
  421. post(EXPORT_DATA_BY_TASK_ID, {
  422. taskIds
  423. }).then(({ data }) => {
  424. downloadFile(data, "任务列表.xlsx");
  425. btnLoading.value = false;
  426. }).catch(err => {
  427. btnLoading.value = false;
  428. globalPopup?.showError(err.msg)
  429. })
  430. }
  431. function closeExportModal() {
  432. exportVisible.value = false;
  433. }
  434. function exportExcel(data: any) {
  435. exportLoading.value = "2";
  436. post(EXPORT_DATA, getFromValue(data)).then(({ data }) => {
  437. downloadFile(data, "任务列表.xlsx");
  438. exportLoading.value = "3";
  439. exportVisible.value = false;
  440. }).catch(err => {
  441. globalPopup?.showError(err.msg)
  442. })
  443. setTimeout(() => {
  444. }, 2000)
  445. }
  446. function editRow(row: any) {
  447. isEdit.value = true;
  448. taskModalVisible.value = true;
  449. let value = {
  450. ...row
  451. }
  452. if (value.executorId) {
  453. value.executorId = value.executorId.split(",")
  454. }
  455. taskForm.value = value;
  456. }
  457. function finishRow(item: any) {
  458. post(UPDATE_TASK_STATUS, {
  459. id: item.id,
  460. status: 2
  461. }).then(() => {
  462. search()
  463. globalPopup?.showSuccess("操作成功")
  464. }).catch(err => {
  465. globalPopup?.showError(err.msg)
  466. })
  467. }
  468. function restartTaksTime() {
  469. const { id, timesList } = restartFrom.value
  470. const date = dayjs().format("YYYY-MM-DD")
  471. if(timesList[0] < date) {
  472. globalPopup?.showInfo("开始时间不能在今天之前")
  473. return
  474. }
  475. post(UPDATE_TASK_STATUS, {
  476. id, status: 0,
  477. startDate: timesList[0],
  478. endDate: timesList[1]
  479. }).then(() => {
  480. search()
  481. globalPopup?.showSuccess("操作成功")
  482. restartPopUpWindowVisable.value = false
  483. }).catch(err => {
  484. globalPopup?.showError(err.msg)
  485. })
  486. }
  487. function restart(item: any) {
  488. const starDate = item.startDate ? item.startDate : dayjs().format("YYYY-MM-DD")
  489. const endDate = item.endDate ? item.endDate : dayjs().format("YYYY-MM-DD")
  490. restartFrom.value = {
  491. ...item,
  492. timesList: [starDate, endDate]
  493. }
  494. restartPopUpWindowVisable.value = true
  495. }
  496. function deleteRow(item: any) {
  497. confirmAction("确定删除吗?").then(() => {
  498. post(DELETE_TASKS, {
  499. taskIds: item.id
  500. }).then(() => {
  501. search();
  502. globalPopup?.showSuccess("删除成功")
  503. }).catch(err => {
  504. console.log("err", err);
  505. globalPopup?.showError(err.msg)
  506. })
  507. })
  508. }
  509. function goDetail(item: any, path: keyof pushMap, typeId: pushMap[keyof pushMap]) {
  510. router.push({
  511. path: `/${path}/detail`,
  512. query: {
  513. id: item[typeId]
  514. }
  515. })
  516. }
  517. onBeforeMount(() => {
  518. pagePermission.value = getFunctionList(MOD);
  519. searchForm.value = { ...defaultSearchForm };
  520. })
  521. onMounted(() => {
  522. search()
  523. })
  524. </script>
  525. <style lang="scss" scoped></style>