فهرست منبع

派单管理静态页面

刘洋 1 سال پیش
والد
کامیت
613035016c

+ 1 - 0
auto-imports.d.ts

@@ -1,6 +1,7 @@
 /* eslint-disable */
 /* prettier-ignore */
 // @ts-nocheck
+// noinspection JSUnusedGlobalSymbols
 // Generated by unplugin-auto-import
 export {}
 declare global {

+ 0 - 2
build/plugins/index.js

@@ -5,7 +5,6 @@ import html from './html';
 import visualizer from './visualizer';
 import compress from './compress';
 import lazyloadCom from './lazyloadCom';
-import lazyloadStyle from './lazyloadStyle';
 import AutoImport from './autoImport';
 import vueSetupExtend from 'unplugin-vue-setup-extend-plus/vite';
 
@@ -20,7 +19,6 @@ export function setupVitePlugins(viteEnv) {
     Unocss(),
     html(viteEnv),
     lazyloadCom,
-    // lazyloadStyle,
     AutoImport,
     requireTransform({}),
     vueSetupExtend(),

+ 0 - 16
build/plugins/lazyloadStyle.js

@@ -1,16 +0,0 @@
-import { createStyleImportPlugin } from 'vite-plugin-style-import';
-
-export default createStyleImportPlugin({
-  libs: [
-    {
-      libraryName: '@arco-design/web-vue',
-      esModule: true,
-      resolveStyle: (name) => {
-        // css
-        // return `@arco-design/web-vue/es/${name}/style/css.js`;
-        // less
-        return `@arco-design/web-vue/es/${name}/style/index.js`;
-      },
-    },
-  ],
-});

+ 5 - 5
components.d.ts

@@ -1,11 +1,11 @@
-// generated by unplugin-vue-components
-// We suggest you to commit this file into source control
+/* eslint-disable */
+/* prettier-ignore */
+// @ts-nocheck
+// Generated by unplugin-vue-components
 // Read more: https://github.com/vuejs/core/pull/3399
-import '@vue/runtime-core'
-
 export {}
 
-declare module '@vue/runtime-core' {
+declare module 'vue' {
   export interface GlobalComponents {
     Chart: typeof import('./src/components/global/chart/index.vue')['default']
     MyDialog: typeof import('./src/components/global/my-dialog/index.vue')['default']

+ 3 - 3
package.json

@@ -29,7 +29,7 @@
     "mockjs": "^1.1.0",
     "nprogress": "^0.2.0",
     "pinia": "^2.0.27",
-    "tdesign-vue-next": "^1.3.8",
+    "tdesign-vue-next": "^1.3.11",
     "tvision-color": "^1.5.0",
     "unplugin-vue-setup-extend-plus": "^1.0.0",
     "vue": "^3.3.4",
@@ -61,8 +61,8 @@
     "rollup-plugin-visualizer": "^5.9.0",
     "typescript": "^4.8.3",
     "unocss": "^0.52.0",
-    "unplugin-auto-import": "^0.15.3",
-    "unplugin-vue-components": "^0.22.4",
+    "unplugin-auto-import": "^0.16.6",
+    "unplugin-vue-components": "^0.25.1",
     "unplugin-vue-define-options": "^0.6.2",
     "vite": "^3.2.5",
     "vite-plugin-compression": "^0.5.1",

+ 8 - 0
src/api/test.js

@@ -0,0 +1,8 @@
+import { request } from '@/utils/request.js';
+
+export const getTableData = (data) =>
+  request({
+    url: '/api/table',
+    method: 'post',
+    data,
+  });

+ 29 - 36
src/api/user.js

@@ -1,38 +1,31 @@
 import { request } from '@/utils/request.js';
 
-export default {
-  login(data = {}) {
-    return request({
-      url: '/api/login',
-      method: 'post',
-      data,
-    });
-  },
-  logout(data = {}) {
-    return request({
-      url: '/api/logout',
-      method: 'post',
-      data,
-    });
-  },
-  getMenus() {
-    return request({
-      url: '/api/getMenus',
-      method: 'get',
-    });
-  },
-  addUser(data = {}) {
-    return request({
-      url: '/api/add',
-      method: 'post',
-      data,
-    });
-  },
-  editUser(data = {}) {
-    return request({
-      url: '/api/edit',
-      method: 'post',
-      data,
-    });
-  },
-};
+export const login = (data) =>
+  request({
+    url: '/api/login',
+    method: 'post',
+    data,
+  });
+export const logout = (data) =>
+  request({
+    url: '/api/logout',
+    method: 'post',
+    data,
+  });
+export const getMenus = () =>
+  request({
+    url: '/api/getMenus',
+    method: 'get',
+  });
+export const addUser = (data) =>
+  request({
+    url: '/api/add',
+    method: 'post',
+    data,
+  });
+export const editUser = (data) =>
+  request({
+    url: '/api/edit',
+    method: 'post',
+    data,
+  });

+ 8 - 12
src/components/global/search-form/components/search-form-item.vue

@@ -33,16 +33,12 @@
   ></template>
   <!-- 文本框 -->
   <template v-if="item.type == undefined || item.type == 'text'">
-    <t-input
-      v-model="searchParam[item.prop]"
-      placeholder="请输入"
-      v-bind="attrs"
-    />
+    <t-input v-model="params[item.prop]" placeholder="请输入" v-bind="attrs" />
   </template>
   <!-- 下拉选择框 -->
   <template v-if="item.type == 'select' || item.type == 'multipleSelect'">
     <t-select
-      v-model="searchParam[item.prop]"
+      v-model="params[item.prop]"
       :multiple="item.type == 'multipleSelect'"
       placeholder="请选择"
       v-bind="attrs"
@@ -61,7 +57,7 @@
     v-if="item.type == 'treeSelect' || item.type == 'multipleTreeSelect'"
   >
     <t-tree-select
-      v-model="searchParam[item.prop]"
+      v-model="params[item.prop]"
       :multiple="item.type == 'multipleTreeSelect'"
       :data="item.options"
       v-bind="attrs"
@@ -70,7 +66,7 @@
   <!-- 日期选择 -->
   <template v-if="item.type == 'date'">
     <t-date-picker
-      v-model="searchParam[item.prop]"
+      v-model="params[item.prop]"
       :mode="item.mode || 'date'"
       value-format="YYYY-MM-DD"
       type="date"
@@ -81,7 +77,7 @@
   <!-- 时间选择 -->
   <template v-if="item.type == 'time'">
     <t-time-picker
-      v-model="searchParam[item.prop]"
+      v-model="params[item.prop]"
       format="HH:mm:ss"
       v-bind="attrs"
     />
@@ -89,14 +85,14 @@
   <!-- 时间范围选择 -->
   <template v-if="item.type == 'timerange'">
     <t-time-range-picker
-      v-model="searchParam[item.prop]"
+      v-model="params[item.prop]"
       format="HH:mm:ss"
       v-bind="attrs"
     />
   </template>
   <!-- 日期范围选择 -->
   <template v-if="item.type == 'daterange'">
-    <t-date-range-picker v-model="searchParam[item.prop]" v-bind="attrs" />
+    <t-date-range-picker v-model="params[item.prop]" v-bind="attrs" />
   </template>
 </template>
 
@@ -105,7 +101,7 @@ import { computed } from 'vue';
 import { ChevronDownIcon } from 'tdesign-icons-vue-next';
 const props = defineProps({
   item: Object,
-  searchParam: Object,
+  params: Object,
 });
 const attrs = computed(() => {
   let obj = {};

+ 54 - 44
src/components/global/search-form/index.vue

@@ -3,11 +3,11 @@
 //其他较复杂的主页面表单场景还是简易手写组件和业务(便于可读性和维护)
 <template>
   <div
-    v-if="columns?.length"
+    v-if="fields?.length"
     class="table-search"
     :class="{ 'in-padding': inPadding }"
   >
-    <t-form ref="formRef" :model="searchParam" :inline="true">
+    <t-form ref="formRef" :model="params" :inline="true">
       <div class="first-row flex">
         <t-form-item
           v-for="item in firstLineItemsFilter"
@@ -17,7 +17,7 @@
           :style="{ width: colToWidth(item.colSpan || 0) }"
           :class="{ 'buttons-wrap': item.type == 'buttons' }"
         >
-          <SearchFormItem :item="item" :search-param="searchParam" />
+          <SearchFormItem :item="item" :params="params" />
         </t-form-item>
         <div class="flex-1"></div>
         <t-form-item
@@ -28,7 +28,7 @@
           :style="{ width: colToWidth(item.colSpan || 0) }"
           :class="{ 'buttons-wrap': item.type == 'buttons' }"
         >
-          <SearchFormItem :item="item" :search-param="searchParam" />
+          <SearchFormItem :item="item" :params="params" />
         </t-form-item>
         <div v-if="showExpandBtn && !showAll" class="flex-1 text-right">
           <t-button
@@ -57,7 +57,7 @@
           :style="{ width: colToWidth(item.colSpan || 0) }"
           :class="{ 'buttons-wrap': item.type == 'buttons' }"
         >
-          <SearchFormItem :item="item" :search-param="searchParam" />
+          <SearchFormItem :item="item" :params="params" />
         </t-form-item>
       </div>
     </t-form>
@@ -101,28 +101,44 @@ onUnmounted(() => {
 
 // 默认值
 const props = defineProps({
-  columns: Object, // 搜索配置列,见下方示例
-  searchParam: Object, // 搜索参数
+  fields: Object, // 搜索配置列,见下方示例
+  params: Object, // 搜索参数
   showAll: Boolean, //是否要求直接展开,无需折叠换行按钮
   inPadding: Boolean,
 });
-//columns示例:(目前支持控件:input、select、dropdown按钮、treeSelect、date选择框、time选择框、timerange时间范围选择框、daterange日期范围选择框...后期可以按需求扩展)
+//fields示例:(目前支持控件:input、select、dropdown按钮、treeSelect、date选择框、time选择框、timerange时间范围选择框、daterange日期范围选择框...后期可以按需求扩展)
 /*
-const exampleColumnsProp = [
-  {
-    prop: 'b',
-    label: '姓名',
-    labelWidth: '60px',
-    colSpan: 3.6,
-  },
-  {
-    prop: 'c',
-    label: '来源',
-    type: 'select',
-    labelWidth: '60px',
-    colSpan: 3.6,
-  },
-  {
+const fields = [
+    {
+      prop: 'b',
+      label: '姓名',
+      labelWidth: '60px',
+      colSpan: 3.6,
+    },
+    {
+      prop: 'c',
+      label: '来源',
+      type: 'select',
+      labelWidth: '60px',
+      colSpan: 3.6,
+    },
+    {
+      type: 'button',
+      text: '查询',
+      attrs: {
+        class: 'm-l-10px',
+      },
+    },
+    {
+      type: 'button',
+      text: '新增',
+      position: 'right',    //搜索条件中可能会有按钮在首行中居右,可以使用position:'right'
+      attrs: {
+        theme: 'success',
+      },
+      onClick: () => {},
+    },
+    {
     type: 'buttons',
     colSpan: 6,
     children: [
@@ -150,19 +166,10 @@ const exampleColumnsProp = [
       },
     ],
   },
-    {
-    type: 'button',
-    text: '新增',
-    position: 'right',    //搜索条件中可能会有按钮在首行中居右,可以使用position:'right'
-    attrs: {
-      theme: 'success',
-    },
-    onClick: () => {},
-  },
 ];
 */
 const showExpandBtn = computed(() => {
-  let allColSpanNum = props.columns.reduce((total, item) => {
+  let allColSpanNum = props.fields.reduce((total, item) => {
     return total + item.colSpan;
   }, 0);
   return allColSpanNum > 24;
@@ -193,8 +200,8 @@ watch(showMore, (val) => {
 const firstLineItems = computed(() => {
   let init = 0;
   let arr = [];
-  for (let i = 0; i < props.columns.length; i++) {
-    let column = props.columns[i];
+  for (let i = 0; i < props.fields.length; i++) {
+    let column = props.fields[i];
     if (init + (column.colSpan || 0) > 24) {
       cutIndex.value = i;
       break;
@@ -213,7 +220,7 @@ const firstLineItemsIsRight = computed(() => {
 });
 
 const otherLineItems = computed(() => {
-  return props.columns?.slice(cutIndex.value) || [];
+  return props.fields?.slice(cutIndex.value) || [];
 });
 const colToWidth = (colSpan) => {
   if (colSpan === 0) {
@@ -227,6 +234,9 @@ const colToWidth = (colSpan) => {
 .table-search {
   padding: 10px;
   background-color: #fff;
+  :deep(.t-date-range-picker) {
+    width: 100%;
+  }
   :deep(.t-form__item.buttons-wrap) {
     .t-form__controls-content {
       .t-button {
@@ -239,14 +249,14 @@ const colToWidth = (colSpan) => {
     overflow: hidden;
     transition: all 0.2s;
   }
-  :deep(
-      .other-rows
-        .t-form__item.buttons-wrap
-        .t-form__controls-content
-        .t-button:first-child
-    ) {
-    margin-left: 0;
-  }
+  // :deep(
+  //     .other-rows
+  //       .t-form__item.buttons-wrap
+  //       .t-form__controls-content
+  //       .t-button:first-child
+  //   ) {
+  //   margin-left: 0;
+  // }
   &.in-padding {
     margin: -10px;
   }

+ 6 - 2
src/hooks/useFetchTable.js

@@ -1,7 +1,7 @@
 import { ref, reactive, watch } from 'vue';
 
 //options参数示例:{ pageSize:20 , params: ref({ a:1, b:2 }) }
-export default function useFetchTable(apiFn, options, immediately = true) {
+export default function useFetchTable(apiFn, options = {}, immediately = true) {
   let pagination = reactive({
     page: 1,
     pageSize: options?.pageSize || 10,
@@ -9,6 +9,7 @@ export default function useFetchTable(apiFn, options, immediately = true) {
   });
   //tdesign的分页器组件的onChange方法,涵盖了页码的change和pageSize的change 两者的监听
   const onChange = (pageInfo) => {
+    console.log('pageInfo:', pageInfo);
     pagination.Size = pageInfo.pageSize;
     pagination.page = pageInfo.current;
   };
@@ -28,12 +29,15 @@ export default function useFetchTable(apiFn, options, immediately = true) {
         ...(options.params?.value || {}),
       };
       let res = await apiFn(params);
+      console.log('res', res);
       //下方代码 后续根据实际接口返回字段进行修改
       let list = Array.isArray(res.list) ? res.list : [];
       tableData.value = list;
       pagination.total = res.total;
       loading.value = false;
-    } catch (err) {}
+    } catch (err) {
+      console.warn('分页请求错误:', err);
+    }
   };
   if (immediately) {
     //默认立即执行一次分页请求,如果不想如此,可以将第三个参数immediately传false

+ 3 - 1
src/hooks/useTableCrud.js

@@ -1,4 +1,5 @@
 import { computed, ref } from 'vue';
+import { cloneDeep } from 'lodash';
 
 const ACTIONS = {
   edit: '编辑',
@@ -9,6 +10,7 @@ export default function (
   { name, doCreate, doUpdate, refresh, initForm = {} },
   formDialogRef
 ) {
+  const saveInitForm = cloneDeep(initForm);
   const visible = ref(false);
   const type = ref('');
   const title = computed(() => ACTIONS[type.value] + name);
@@ -20,7 +22,7 @@ export default function (
   function handleAdd() {
     type.value = 'add';
     visible.value = true;
-    formData.value = { ...initForm };
+    formData.value = cloneDeep(saveInitForm);
   }
 
   //编辑

+ 4 - 1
src/layout/index.vue

@@ -14,7 +14,7 @@
       </div> -->
       <left-menu></left-menu>
     </t-aside>
-    <t-layout class="right-content">
+    <t-layout class="right-view">
       <t-header class="layout-header">
         <div class="h-full header-wrap flex items-center justify-between">
           <div class="flex-1">
@@ -90,6 +90,9 @@ const colorChoose = (data) => {
 
 <style lang="less" scoped>
 .app-layout {
+  .right-view {
+    overflow: auto;
+  }
   .t-layout__sider {
     //重写过渡时长,让其余menu的折叠动画保持同步
     transition: all 0.28s cubic-bezier(0.645, 0.045, 0.355, 1);

+ 28 - 4
src/mock/index.js

@@ -6,7 +6,7 @@ const menusList = [
   //   title: '用户管理',
   //   parentId: -1,
   //   url: '/userManage',
-  //   sort: 1,
+  //   sort: 2,
   //   icon: null,
   //   name: 'UserManage',
   // },
@@ -23,7 +23,7 @@ const menusList = [
     id: 1,
     title: '服务单元管理',
     parentId: -1,
-    url: '/serviceUnitManage',
+    url: '/service-unit-manage',
     sort: 1,
     name: 'ServiceUnitManage',
   },
@@ -31,7 +31,7 @@ const menusList = [
     id: 2,
     title: '派单管理',
     parentId: 1,
-    url: '/serviceUnitManage/dispatch',
+    url: '/service-unit-manage/dispatch',
     sort: 1,
     name: 'Dispatch',
   },
@@ -39,7 +39,7 @@ const menusList = [
     id: 3,
     title: '派单管理',
     parentId: 2,
-    url: '/serviceUnitManage/dispatch/dispatchManage',
+    url: '/service-unit-manage/dispatch/dispatch-manage',
     sort: 1,
     name: 'DispatchManage',
   },
@@ -67,3 +67,27 @@ export const editApi = Mock.mock('/api/edit', 'post', (data) => {
     ok: true,
   };
 });
+
+//模拟一个分页请求
+export const tableApi = Mock.mock('/api/table', 'post', (data) => {
+  return {
+    list: [
+      {
+        a: 1,
+        b: 2,
+        c: 3,
+        d: 4,
+        e: 5,
+        f: 6,
+        g: 7,
+        h: 8,
+        i: 9,
+        j: 10,
+        k: 11,
+        l: 12,
+        m: 13,
+      },
+    ],
+    total: 80,
+  };
+});

+ 8 - 6
src/router/modules/serviceUnitManage.js

@@ -1,7 +1,7 @@
 export default {
   name: 'ServiceUnitManage',
-  path: '/serviceUnitManage',
-  redirect: '/serviceUnitManage/dispatch',
+  path: '/service-unit-manage',
+  redirect: '/service-unit-manage/dispatch',
   meta: {
     title: '服务单元管理',
     sort: 1,
@@ -10,8 +10,8 @@ export default {
   children: [
     {
       name: 'Dispatch',
-      path: '/serviceUnitManage/dispatch',
-      redirect: '/serviceUnitManage/dispatch/dispatchManage',
+      path: '/service-unit-manage/dispatch',
+      redirect: '/service-unit-manage/dispatch/dispatch-manage',
       meta: {
         title: '派单管理',
         sort: 1,
@@ -20,9 +20,11 @@ export default {
       children: [
         {
           name: 'DispatchManage',
-          path: '/serviceUnitManage/dispatch/dispatchManage',
+          path: '/service-unit-manage/dispatch/dispatch-manage',
           component: () =>
-            import('@/views/serviceUnitManage/dispatchManage/index.vue'),
+            import(
+              '@/views/service-unit-manage/dispatch/dispatch-manage/index.vue'
+            ),
           meta: {
             title: '派单管理',
             sort: 1,

+ 1 - 1
src/router/routes.js

@@ -4,7 +4,7 @@ const routes = [
     name: 'Layout',
     path: '/',
     component: () => import('@/layout/index.vue'),
-    redirect: '/serviceUnitManage',
+    redirect: '/service-unit-manage',
     children: [],
     meta: {
       title: '',

+ 4 - 6
src/store/modules/user.js

@@ -1,6 +1,6 @@
 import { defineStore } from 'pinia';
 import { cloneDeep } from 'lodash';
-import userApi from '@/api/user';
+import { getMenus, logout, login } from '@/api/user';
 import router from '@/router/index';
 import asyncRoutes from '@/router/asyncRoutes';
 import { getTreeList, local } from '@/utils/tool';
@@ -127,8 +127,7 @@ const useUserStore = defineStore('user', {
 
     requestUserMenu() {
       return new Promise((resolve, reject) => {
-        userApi
-          .getMenus()
+        getMenus()
           .then((response) => {
             if (!response) {
               router.push({ name: 'Login' });
@@ -148,8 +147,7 @@ const useUserStore = defineStore('user', {
     },
 
     login(form) {
-      return userApi
-        .login(form)
+      return login(form)
         .then((r) => {
           this.setToken(r.token);
           return true;
@@ -161,7 +159,7 @@ const useUserStore = defineStore('user', {
     },
 
     async logout() {
-      await userApi.logout();
+      await logout();
       this.clearToken();
       this.resetUserInfo();
     },

+ 8 - 17
src/style/global.less

@@ -1,5 +1,6 @@
 @import 'animation.less';
 @import 'reset.less';
+@import 'tdesign-reset.less';
 html,
 body {
   height: 100%;
@@ -13,23 +14,6 @@ body {
   min-width: 1200px;
 }
 
-.t-table {
-  margin-top: 10px;
-}
-.t-form__item {
-  margin-bottom: 15px;
-}
-.t-dialog--default {
-  padding-top: 20px;
-}
-.t-dialog__body {
-  padding-top: 25px;
-}
-
-.t-date-picker__panel .t-pagination-mini .t-pagination-mini__current {
-  display: none;
-}
-
 .layout-header {
   width: 100%;
   // box-shadow: 1px 1px 2px var(--color-neutral-2);
@@ -57,3 +41,10 @@ body {
   min-height: 100%;
   overflow: auto;
 }
+.btn-group {
+  & > .t-button {
+    &:not(:first-child) {
+      margin-left: 10px;
+    }
+  }
+}

+ 26 - 0
src/style/tdesign-reset.less

@@ -0,0 +1,26 @@
+.t-table {
+  margin-top: 10px;
+  .table-operations {
+    text-align: center;
+    & > .t-link:not(:first-child) {
+      margin-left: 15px;
+    }
+  }
+}
+.t-form__item {
+  margin-bottom: 15px;
+}
+.t-dialog--default {
+  padding-top: 20px;
+}
+.t-dialog__body {
+  padding-top: 25px;
+}
+
+.t-date-picker__panel .t-pagination-mini .t-pagination-mini__current {
+  display: none;
+}
+.t-dialog__ctx .t-dialog__position.t-dialog--top {
+  padding: 0;
+  align-items: center;
+}

+ 2 - 5
src/views/examManage/index.vue

@@ -1,9 +1,6 @@
 <template>
   <div class="exam-manage flex flex-col">
-    <SearchForm
-      :columns="searchColumns"
-      :searchParam="searchParam"
-    ></SearchForm>
+    <SearchForm :fields="searchColumns" :params="params"></SearchForm>
     <div class="flex-1 page-wrap">
       <t-table
         size="small"
@@ -131,7 +128,7 @@ const searchColumns = ref([
     },
   },
 ]);
-const searchParam = reactive({
+const params = reactive({
   a: '',
   b: '',
   c: '',

+ 68 - 0
src/views/service-unit-manage/dispatch/dispatch-manage/create-dispatch-dialog.vue

@@ -0,0 +1,68 @@
+<template>
+  <my-dialog
+    :visible="visible"
+    @close="emit('update:visible', false)"
+    :header="title"
+    :width="600"
+    labelWidth="140px"
+    :closeOnOverlayClick="false"
+  >
+    <t-form ref="formRef" :model="formData">
+      <t-form-item label="项目单号:">
+        <t-input v-model="formData.a"></t-input>
+      </t-form-item>
+      <t-form-item label="项目名称:">
+        <t-input v-model="formData.b"></t-input>
+      </t-form-item>
+      <t-form-item label="派单时间:">
+        <t-date-picker v-model="formData.c" />
+      </t-form-item>
+      <t-form-item label="服务单元名称:">
+        <t-select v-model="formData.d"></t-select>
+      </t-form-item>
+      <t-form-item label="派单人:">
+        <t-select v-model="formData.e"></t-select>
+      </t-form-item>
+      <t-form-item label="客户类型:">
+        <t-select v-model="formData.f"></t-select>
+      </t-form-item>
+      <t-form-item label="客户名称:">
+        <t-select v-model="formData.g"></t-select>
+      </t-form-item>
+      <t-form-item label="考试开始时间">
+        <t-date-picker v-model="formData.h" />
+      </t-form-item>
+      <t-form-item label="考试结束时间">
+        <t-date-picker v-model="formData.i" />
+      </t-form-item>
+      <t-form-item label="实施产品:">
+        <t-select v-model="formData.j"></t-select>
+      </t-form-item>
+      <t-form-item label="大区经理:">
+        <t-select v-model="formData.k"></t-select>
+      </t-form-item>
+    </t-form>
+    <template #foot>
+      <t-button theme="default" @click="emit('update:visible', false)"
+        >取消</t-button
+      >
+      <t-button theme="primary" @click="handleSave">保存</t-button>
+    </template>
+  </my-dialog>
+</template>
+<script setup name="CreateDispatchDialog">
+import { ref } from 'vue';
+const emit = defineEmits(['update:visible']);
+const formRef = ref(null);
+
+const props = defineProps({
+  visible: Boolean,
+  title: String,
+  type: String,
+  handleSave: Function,
+  formData: Object,
+});
+defineExpose({
+  formRef,
+});
+</script>

+ 221 - 0
src/views/service-unit-manage/dispatch/dispatch-manage/index.vue

@@ -0,0 +1,221 @@
+<template>
+  <div class="dispatch-manage flex flex-col">
+    <SearchForm :fields="fields" :params="params"></SearchForm>
+    <div class="flex-1 page-wrap">
+      <div class="table-handle btn-group">
+        <t-button @click="handleAdd">新增</t-button>
+        <t-button>作废</t-button>
+        <t-button>批量划定</t-button>
+      </div>
+      <t-table
+        size="small"
+        row-key="id"
+        :columns="columns"
+        :data="tableData"
+        bordered
+        :pagination="{
+          defaultCurrent: 1,
+          defaultPageSize: 10,
+          onChange,
+          total: pagination.total,
+        }"
+        :selected-row-keys="selectedRowKeys"
+        select-on-row-click
+        @select-change="selectChange"
+      >
+      </t-table>
+    </div>
+
+    <CreateDispatchDialog
+      v-model:visible="showCreateDispatchDialog"
+      :title="title"
+      :type="type"
+      :handleSave="handleSave"
+      :formData="formData"
+      ref="formDialogRef"
+    ></CreateDispatchDialog>
+  </div>
+</template>
+
+<script setup lang="jsx" name="DispatchManage">
+import { reactive, ref } from 'vue';
+import { useRequest } from 'vue-request';
+import { getTableData } from '@/api/test';
+import useFetchTable from '@/hooks/useFetchTable';
+import useTableCrud from '@/hooks/useTableCrud';
+import CreateDispatchDialog from './create-dispatch-dialog.vue';
+
+const formDialogRef = ref(null);
+const selectedRowKeys = ref([]);
+const selectChange = (value, { selectedRowData }) => {
+  selectedRowKeys.value = value;
+};
+const columns = [
+  {
+    colKey: 'row-select',
+    type: 'multiple',
+    width: 50,
+    fixed: 'left',
+  },
+  { colKey: 'a', title: '服务单元', width: 80 },
+  { colKey: 'b', title: '项目单号', width: 80 },
+  { colKey: 'c', title: '派单时间', width: 80 },
+  { colKey: 'd', title: '派单人', width: 70 },
+  { colKey: 'e', title: '客户类型', width: 80 },
+  { colKey: 'f', title: '客户名称', width: 80 },
+  { colKey: 'g', title: '项目名称', width: 80 },
+  { colKey: 'h', title: '实施产品', width: 80 },
+  { colKey: 'i', title: '考试开始时间', width: 140 },
+  { colKey: 'j', title: '考试结束时间', width: 140 },
+  { colKey: 'k', title: '大区经理', width: 80 },
+  { colKey: 'l', title: '提交人', width: 70 },
+  { colKey: 'm', title: '提交时间', width: 140 },
+  {
+    title: '操作',
+    colKey: 'operate',
+    fixed: 'right',
+    width: 200,
+    cell: (h, { row }) => {
+      return (
+        <div class="table-operations">
+          <t-link theme="primary" hover="color">
+            划定
+          </t-link>
+          <t-link
+            theme="primary"
+            hover="color"
+            onClick={(e) => {
+              e.stopPropagation();
+              handleEdit(row);
+            }}
+          >
+            修改
+          </t-link>
+          <t-link theme="primary" hover="color">
+            重新划定
+          </t-link>
+        </div>
+      );
+    },
+  },
+];
+
+const fields = ref([
+  {
+    prop: 'a',
+    label: '服务单元',
+    type: 'select',
+    labelWidth: '80px',
+    colSpan: 5,
+  },
+  {
+    prop: 'b',
+    label: '大区经理',
+    type: 'select',
+    labelWidth: '80px',
+    colSpan: 5,
+  },
+  {
+    prop: 'c',
+    label: '派单人',
+    type: 'select',
+    labelWidth: '80px',
+    colSpan: 5,
+  },
+  {
+    prop: 'd',
+    label: '客户类型',
+    type: 'select',
+    labelWidth: '80px',
+    colSpan: 5,
+  },
+  {
+    type: 'buttons',
+    colSpan: 3,
+    children: [
+      {
+        type: 'button',
+        text: '查询',
+      },
+    ],
+  },
+  {
+    prop: 'e',
+    label: '客户名称',
+    labelWidth: '80px',
+    colSpan: 5,
+  },
+  {
+    prop: 'f',
+    label: '项目单号',
+    labelWidth: '80px',
+    colSpan: 5,
+  },
+  {
+    prop: 'g',
+    label: '派单时间',
+    type: 'daterange',
+    labelWidth: '80px',
+    colSpan: 10,
+  },
+]);
+const params = reactive({
+  a: '',
+  b: '',
+  c: '',
+  d: '',
+  e: '',
+  f: '',
+  g: [],
+});
+
+const {
+  loading: tableLoading,
+  pagination,
+  tableData,
+  fetchData,
+  onChange,
+} = useFetchTable(getTableData);
+
+const add = async () => {
+  await 1;
+  alert(1);
+};
+const update = async () => {};
+const refresh = async () => {};
+
+const {
+  visible: showCreateDispatchDialog,
+  type,
+  title,
+  loading: dialogLoading,
+  handleAdd,
+  handleEdit,
+  handleSave,
+  formData,
+  formRef,
+} = useTableCrud(
+  {
+    name: '派单',
+    doCreate: add,
+    doUpdate: update,
+    refresh: refresh,
+    initForm: {
+      a: '',
+      b: '',
+      c: '',
+      d: '',
+      e: '',
+      f: '',
+      g: '',
+      h: '',
+      i: '',
+      j: '',
+      k: '',
+    },
+  },
+  formDialogRef
+);
+</script>
+
+<style></style>

+ 0 - 13
src/views/serviceUnitManage/dispatch/dispatchManage/index.vue

@@ -1,13 +0,0 @@
-<template>
-  <div class="dispatch-manage">派单管理</div>
-</template>
-
-<script setup>
-import userApi from '@/api/user';
-import { useRequest } from 'vue-request';
-
-const { loading, data } = useRequest(userApi.getMenus);
-console.log('ddd', data);
-</script>
-
-<style></style>

+ 2 - 5
src/views/userManage/index.vue

@@ -1,9 +1,6 @@
 <template>
   <div class="user-manage flex flex-col">
-    <SearchForm
-      :columns="searchColumns"
-      :searchParam="searchParam"
-    ></SearchForm>
+    <SearchForm :fields="searchColumns" :params="params"></SearchForm>
 
     <div class="flex-1 page-wrap">
       <t-table
@@ -275,7 +272,7 @@ const searchColumns = ref([
     ],
   },
 ]);
-const searchParam = reactive({
+const params = reactive({
   a: '',
   b: '',
   c: '',