Jelajahi Sumber

静态页面开发

刘洋 1 tahun lalu
induk
melakukan
f2035d351c

+ 2 - 0
components.d.ts

@@ -41,6 +41,8 @@ declare module 'vue' {
     TTabs: typeof import('tdesign-vue-next')['Tabs']
     TTimePicker: typeof import('tdesign-vue-next')['TimePicker']
     TTimeRangePicker: typeof import('tdesign-vue-next')['TimeRangePicker']
+    TTransfer: typeof import('tdesign-vue-next')['Transfer']
+    TTree: typeof import('tdesign-vue-next')['Tree']
     TTreeSelect: typeof import('tdesign-vue-next')['TreeSelect']
     TUpload: typeof import('tdesign-vue-next')['Upload']
   }

+ 0 - 2
src/hooks/useFetchTable.js

@@ -9,7 +9,6 @@ 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;
   };
@@ -29,7 +28,6 @@ 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;

+ 1 - 1
src/hooks/useTableCrud.js

@@ -2,7 +2,7 @@ import { computed, ref } from 'vue';
 import { cloneDeep } from 'lodash';
 
 const ACTIONS = {
-  edit: '编辑',
+  edit: '修改',
   add: '新增',
 };
 

+ 1 - 5
src/layout/index.vue

@@ -46,12 +46,8 @@
         </div>
       </t-header>
       <t-content class="layout-content overflow-auto">
-        <!-- <transition name="slide-down" mode="out-in">
-          <router-view></router-view>
-        </transition> -->
-
         <router-view v-slot="{ Component }">
-          <transition name="slide-down" mode="out-in" appear>
+          <transition name="fade-slide" mode="out-in" appear>
             <component :is="Component" />
           </transition>
         </router-view>

+ 18 - 1
src/mock/index.js

@@ -41,6 +41,22 @@ const menusList = [
     sort: 1,
     name: 'UnitManage',
   },
+  {
+    id: 6,
+    title: '服务范围管理',
+    parentId: 4,
+    url: '/service-unit-manage/service-unit/range-manage',
+    sort: 2,
+    name: 'RangeManage',
+  },
+  {
+    id: 7,
+    title: '服务区域规划',
+    parentId: 4,
+    url: '/service-unit-manage/service-unit/regional-planning',
+    sort: 3,
+    name: 'RegionalPlanning',
+  },
 ];
 
 export const menusApi = Mock.mock('/api/getMenus', 'get', () => {
@@ -69,11 +85,12 @@ export const editApi = Mock.mock('/api/edit', 'post', (data) => {
 //模拟一个分页请求
 export const tableApi = Mock.mock('/api/table', 'post', (data) => {
   return {
+    // list: [],
     list: [
       {
         a: 1,
         b: 2,
-        c: 3,
+        c: [],
         d: 4,
         e: 5,
         f: 6,

+ 26 - 0
src/router/modules/serviceUnitManage.js

@@ -56,6 +56,32 @@ export default {
             icon: 'bulletpoint',
           },
         },
+        {
+          name: 'RangeManage',
+          path: '/service-unit-manage/service-unit/range-manage',
+          component: () =>
+            import(
+              '@/views/service-unit-manage/service-unit/range-manage/index.vue'
+            ),
+          meta: {
+            title: '服务范围管理',
+            sort: 2,
+            icon: 'bulletpoint',
+          },
+        },
+        {
+          name: 'RegionalPlanning',
+          path: '/service-unit-manage/service-unit/regional-planning',
+          component: () =>
+            import(
+              '@/views/service-unit-manage/service-unit/regional-planning/index.vue'
+            ),
+          meta: {
+            title: '服务区域规划',
+            sort: 3,
+            icon: 'bulletpoint',
+          },
+        },
       ],
     },
   ],

+ 0 - 12
src/router/routes.js

@@ -15,18 +15,6 @@ const routes = [
     path: '/login',
     component: () => import('@/views/login/index.vue'),
     meta: { title: '登录' },
-    children: [
-      {
-        name: 'ExamSelect',
-        path: '/login/examSelect',
-        component: () => import('@/views/login/examSelect/index.vue'),
-      },
-      {
-        name: 'subjectSelect',
-        path: '/login/subject-select',
-        component: () => import('@/views/login/subjectSelect/index.vue'),
-      },
-    ],
   },
 
   {

+ 0 - 2
src/store/modules/user.js

@@ -119,10 +119,8 @@ const useUserStore = defineStore('user', {
     },
     setMenu(data) {
       const menus = filterAsyncRouter(getTreeList(data));
-      console.log('menus', menus);
       this.menus = menus;
       const routers = flatAsyncRoutes(cloneDeep(menus));
-      console.log('routers', routers);
       this.routers = routers;
       routers.map((item) => router.addRoute('Layout', item));
       if (menus.length) {

+ 16 - 0
src/style/animation.less

@@ -48,3 +48,19 @@
 .drop-down-leave-top {
   height: 100px;
 }
+
+/* fade-slide */
+.fade-slide-leave-active,
+.fade-slide-enter-active {
+  transition: all 0.28s cubic-bezier(0.645, 0.045, 0.355, 1);
+}
+
+.fade-slide-enter-from {
+  transform: translateX(-20px);
+  opacity: 0;
+}
+
+.fade-slide-leave-to {
+  transform: translateX(20px);
+  opacity: 0;
+}

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

@@ -24,3 +24,9 @@
   padding: 0;
   align-items: center;
 }
+.t-table__empty-row > td {
+  padding: 0 !important;
+  .t-table__empty {
+    min-height: 40px;
+  }
+}

+ 1 - 2
src/utils/request.js

@@ -86,8 +86,7 @@ function stringify(data) {
  */
 function createRequest(service) {
   return function (config) {
-    console.log('import.meta.env:', import.meta.env);
-    const { env } = import.meta;
+    const env = import.meta.env;
     const token = local.get(env.VITE_APP_TOKEN_PREFIX);
     const configDefault = {
       headers: {

+ 0 - 98
src/views/login/examSelect/index.vue

@@ -1,98 +0,0 @@
-<template>
-  <div class="exam-select">
-    <h1>请选择考试批次</h1>
-
-    <t-form
-      ref="form"
-      :data="formData"
-      :label-width="0"
-      class="form"
-      :rules="rules"
-    >
-      <t-form-item name="examId">
-        <t-select
-          v-model="formData.examId"
-          placeholder="请选择考试"
-          :options="options"
-          filterable
-          :onChange="examChange"
-        />
-      </t-form-item>
-    </t-form>
-    <div class="btns">
-      <a class="confirm" @click="confirm">确 定</a>
-      <a class="cancel" @click="cancel">退 出</a>
-    </div>
-  </div>
-</template>
-
-<script setup name="Login">
-import { ref, reactive } from 'vue';
-import { useRouter } from 'vue-router';
-const form = ref(null);
-const router = useRouter();
-const { replace } = router;
-const formData = reactive({
-  examId: '',
-});
-const examChange = () => {};
-const rules = {
-  examId: [
-    { required: true, message: '请选择考试', type: 'error', trigger: 'change' },
-  ],
-};
-const options = ref([]);
-const confirm = () => {
-  form.value.validate().then(async (result) => {
-    if (result === true) {
-    }
-    setTimeout(() => {
-      router.push('/');
-    }, 100);
-  });
-};
-const cancel = () => {
-  replace('/login');
-};
-</script>
-<style lang="less" scoped>
-.exam-select {
-  position: absolute;
-  left: 0;
-  top: 0;
-  width: 100%;
-  height: 100%;
-  padding: 95px 130px;
-  z-index: 10;
-  .btns {
-    margin-top: 40px;
-  }
-  .btns a {
-    display: inline-block;
-    width: 160px;
-    height: 54px;
-    text-align: center;
-    line-height: 54px;
-    border-radius: 26px;
-
-    font-size: 20px;
-    color: #fff;
-    font-weight: 700;
-    cursor: pointer;
-    &.confirm {
-      background-image: linear-gradient(to right, #88d3fc, #66ade8);
-    }
-    &.cancel {
-      background: #c7cacc;
-      margin-left: 5px;
-    }
-  }
-  .form {
-    margin-top: 40px;
-  }
-  & > h1 {
-    font-size: 23px;
-    text-align: center;
-  }
-}
-</style>

+ 1 - 3
src/views/login/index.vue

@@ -111,9 +111,7 @@ const loginHandle = () => {
   form.value.validate().then(async (result) => {
     const redirect = route.query.redirect
       ? route.query.redirect
-      : loginMode.value === 'admin'
-      ? '/login/examSelect'
-      : '/login/subjectSelect';
+      : '/service-unit-manage';
     if (result === true) {
       await userStore.login({});
       router.push(redirect);

+ 0 - 111
src/views/login/subjectSelect/index.vue

@@ -1,111 +0,0 @@
-<template>
-  <div class="subject-select">
-    <h1>请选择评卷科目</h1>
-
-    <t-form
-      ref="form"
-      :data="formData"
-      :label-width="0"
-      class="form"
-      :rules="rules"
-    >
-      <t-form-item name="examId">
-        <t-select
-          v-model="formData.selectId"
-          placeholder="请选择考试"
-          :options="options1"
-          filterable
-          :onChange="examChange"
-        />
-      </t-form-item>
-      <t-form-item name="subjectId">
-        <t-select
-          v-model="formData.subjectId"
-          placeholder="请选择考试"
-          :options="options2"
-          filterable
-          :onChange="subjectChange"
-        />
-      </t-form-item>
-      <t-form-item name="groupId">
-        <t-select
-          v-model="formData.groupId"
-          placeholder="请选择分组"
-          :options="options3"
-          filterable
-        />
-      </t-form-item>
-    </t-form>
-    <div class="btns">
-      <a class="confirm" @click="confirm">确 定</a>
-      <a class="cancel" @click="cancel">退 出</a>
-    </div>
-  </div>
-</template>
-
-<script setup name="Login">
-import { ref, reactive } from 'vue';
-import { useRouter } from 'vue-router';
-
-const { replace } = useRouter();
-const formData = reactive({
-  examId: '',
-  subjectId: '',
-  groupId: '',
-});
-const examChange = () => {};
-const subjectChange = () => {};
-const rules = {
-  examId: [
-    { required: true, message: '请选择考试', type: 'error', trigger: 'change' },
-  ],
-};
-const options1 = ref([]);
-const options2 = ref([]);
-const options3 = ref([]);
-const confirm = () => {};
-const cancel = () => {
-  replace('/login');
-};
-</script>
-<style lang="less" scoped>
-.subject-select {
-  position: absolute;
-  left: 0;
-  top: 0;
-  width: 100%;
-  height: 100%;
-  padding: 95px 130px;
-  z-index: 10;
-  .btns {
-    margin-top: 40px;
-  }
-  .btns a {
-    display: inline-block;
-    width: 160px;
-    height: 54px;
-    text-align: center;
-    line-height: 54px;
-    border-radius: 26px;
-
-    font-size: 20px;
-    color: #fff;
-    font-weight: 700;
-    cursor: pointer;
-    &.confirm {
-      background-image: linear-gradient(to right, #88d3fc, #66ade8);
-    }
-    &.cancel {
-      background: #c7cacc;
-      margin-left: 5px;
-    }
-  }
-  .form {
-    margin-top: 40px;
-  }
-  & > h1 {
-    font-size: 23px;
-    text-align: center;
-  }
-}
-</style>

+ 1 - 1
src/views/service-unit-manage/dispatch/dispatch-manage/create-dispatch-dialog.vue → src/views/service-unit-manage/dispatch/dispatch-manage/add-dispatch-dialog.vue

@@ -50,7 +50,7 @@
     </template>
   </my-dialog>
 </template>
-<script setup name="CreateDispatchDialog">
+<script setup name="AddDispatchDialog">
 import { ref } from 'vue';
 const emit = defineEmits(['update:visible']);
 const formRef = ref(null);

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

@@ -2,10 +2,10 @@
   <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 class="btn-group">
+        <t-button theme="success" @click="handleAdd">新增</t-button>
+        <t-button theme="success">作废</t-button>
+        <t-button theme="success">批量划定</t-button>
       </div>
       <t-table
         size="small"
@@ -26,14 +26,14 @@
       </t-table>
     </div>
 
-    <CreateDispatchDialog
-      v-model:visible="showCreateDispatchDialog"
+    <AddDispatchDialog
+      v-model:visible="showAddDispatchDialog"
       :title="title"
       :type="type"
       :handleSave="handleSave"
       :formData="formData"
       ref="formDialogRef"
-    ></CreateDispatchDialog>
+    ></AddDispatchDialog>
   </div>
 </template>
 
@@ -43,7 +43,7 @@ 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';
+import AddDispatchDialog from './add-dispatch-dialog.vue';
 
 const formDialogRef = ref(null);
 const selectedRowKeys = ref([]);
@@ -185,7 +185,7 @@ const update = async () => {};
 const refresh = async () => {};
 
 const {
-  visible: showCreateDispatchDialog,
+  visible: showAddDispatchDialog,
   type,
   title,
   loading: dialogLoading,

+ 113 - 0
src/views/service-unit-manage/service-unit/range-manage/index.vue

@@ -0,0 +1,113 @@
+<template>
+  <div class="unit-manage flex flex-col">
+    <SearchForm :fields="fields" :params="params"></SearchForm>
+    <div class="flex-1 page-wrap">
+      <div class="btn-group">
+        <t-button theme="success">新增服务范围</t-button>
+      </div>
+      <t-table
+        size="small"
+        row-key="id"
+        :columns="columns"
+        :data="tableData"
+        bordered
+        :pagination="{
+          defaultCurrent: 1,
+          defaultPageSize: 10,
+          onChange,
+          total: pagination.total,
+        }"
+      >
+      </t-table>
+    </div>
+  </div>
+</template>
+
+<script setup lang="jsx" name="RangeManage">
+import { ref, reactive } from 'vue';
+import { getTableData } from '@/api/test';
+import useFetchTable from '@/hooks/useFetchTable';
+
+const columns = [
+  { colKey: 'a', title: '项目单号', width: 120 },
+  { colKey: 'b', title: '客户名称', minWidth: 100 },
+  { colKey: 'c', title: '客户类型', width: 90 },
+  { colKey: 'd', title: '业务类型', minWidth: 100 },
+  { colKey: 'e', title: '省份', minWidth: 60 },
+  { colKey: 'f', title: '城市', minWidth: 60 },
+  { colKey: 'g', title: '区县', minWidth: 60 },
+  { colKey: 'h', title: '服务档位', width: 90 },
+  {
+    title: '操作',
+    colKey: 'operate',
+    fixed: 'right',
+    width: 120,
+    cell: (h, { row }) => {
+      return (
+        <div class="table-operations">
+          <t-link theme="primary" hover="color">
+            移除
+          </t-link>
+        </div>
+      );
+    },
+  },
+];
+const {
+  loading: tableLoading,
+  pagination,
+  tableData,
+  fetchData,
+  onChange,
+} = useFetchTable(getTableData);
+
+const refresh = async () => {};
+
+const fields = ref([
+  {
+    prop: 'a',
+    label: '服务单元名称',
+    type: 'select',
+    labelWidth: '100px',
+    colSpan: 5,
+  },
+  {
+    prop: 'b',
+    label: '区域',
+    type: 'select',
+    labelWidth: '100px',
+    colSpan: 5,
+  },
+  {
+    prop: 'c',
+    label: '客户类型',
+    type: 'select',
+    labelWidth: '100px',
+    colSpan: 5,
+  },
+  {
+    prop: 'd',
+    label: '客户名称',
+    labelWidth: '100px',
+    colSpan: 5,
+  },
+  {
+    type: 'buttons',
+    colSpan: 2,
+    children: [
+      {
+        type: 'button',
+        text: '查询',
+      },
+    ],
+  },
+]);
+const params = reactive({
+  a: '',
+  b: '',
+  c: '',
+  d: '',
+});
+</script>
+
+<style></style>

+ 85 - 0
src/views/service-unit-manage/service-unit/regional-planning/add-region-dialog.vue

@@ -0,0 +1,85 @@
+<template>
+  <my-dialog
+    :visible="visible"
+    @close="emit('update:visible', false)"
+    :header="title"
+    :width="750"
+    labelWidth="140px"
+    :closeOnOverlayClick="false"
+  >
+    <t-form ref="formRef" :model="formData" layout="inline">
+      <t-form-item label="服务单元名称">
+        <t-select v-model="formData.a"> </t-select>
+      </t-form-item>
+      <t-form-item label="大区经理">
+        <t-select v-model="formData.b"> </t-select>
+      </t-form-item>
+      <t-transfer
+        v-model="formData.c"
+        v-model:checked="checkedRef"
+        :data="leftData"
+        @change="onChange"
+        @checked-change="handleCheckedChange"
+        style="margin: 15px auto 0"
+      >
+        <template #tree="slotProps">
+          <t-tree v-bind="slotProps" checkable hover expand-all transition />
+        </template>
+      </t-transfer>
+    </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="AddRegionDialog">
+import { ref } from 'vue';
+const emit = defineEmits(['update:visible']);
+const formRef = ref(null);
+const checkedRef = ref([]);
+const leftData = [
+  { value: 1, label: '1' },
+  {
+    value: 2,
+    label: '2',
+    children: [
+      {
+        value: 2.1,
+        label: '21',
+      },
+    ],
+  },
+];
+const handleCheckedChange = ({
+  checked,
+  sourceChecked,
+  targetChecked,
+  type,
+}) => {
+  checkedRef.value = checked;
+  console.log('handleCheckedChange', {
+    checked,
+    sourceChecked,
+    targetChecked,
+    type,
+  });
+};
+
+const onChange = (newTargetValue) => {
+  console.log('onChange', newTargetValue);
+};
+
+const props = defineProps({
+  visible: Boolean,
+  title: String,
+  type: String,
+  handleSave: Function,
+  formData: Object,
+});
+defineExpose({
+  formRef,
+});
+</script>

+ 161 - 0
src/views/service-unit-manage/service-unit/regional-planning/index.vue

@@ -0,0 +1,161 @@
+<template>
+  <div class="unit-manage flex flex-col">
+    <SearchForm :fields="fields" :params="params"></SearchForm>
+    <div class="flex-1 page-wrap">
+      <div class="btn-group">
+        <t-button theme="success" @click="handleAdd">新增</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>
+
+    <AddRegionDialog
+      v-model:visible="showAddRegionDialog"
+      :title="title"
+      :type="type"
+      :handleSave="handleSave"
+      :formData="formData"
+      ref="formDialogRef"
+    ></AddRegionDialog>
+  </div>
+</template>
+
+<script setup lang="jsx" name="RegionalPlanning">
+import { ref, reactive } from 'vue';
+import { getTableData } from '@/api/test';
+import useFetchTable from '@/hooks/useFetchTable';
+import useTableCrud from '@/hooks/useTableCrud';
+import AddRegionDialog from './add-region-dialog.vue';
+const formDialogRef = ref(null);
+const selectedRowKeys = ref([]);
+const selectChange = (value, { selectedRowData }) => {
+  selectedRowKeys.value = value;
+};
+
+const columns = [
+  { colKey: 'a', title: '服务单元', minWidth: 150 },
+  { colKey: 'b', title: '大区经理', minWidth: 80 },
+  { colKey: 'c', title: '区域划分', minWidth: 150 },
+  { colKey: 'd', title: '派单共计', minWidth: 80 },
+  {
+    title: '操作',
+    colKey: 'operate',
+    fixed: 'right',
+    width: 150,
+    cell: (h, { row }) => {
+      return (
+        <div class="table-operations">
+          <t-link
+            theme="primary"
+            hover="color"
+            onClick={(e) => {
+              e.stopPropagation();
+              handleEdit(row);
+            }}
+          >
+            修改大区
+          </t-link>
+          <t-link theme="primary" hover="color">
+            删除
+          </t-link>
+        </div>
+      );
+    },
+  },
+];
+const {
+  loading: tableLoading,
+  pagination,
+  tableData,
+  fetchData,
+  onChange,
+} = useFetchTable(getTableData);
+
+const add = async () => {
+  await 1;
+  alert(1);
+};
+const update = async () => {};
+const refresh = async () => {};
+
+const {
+  visible: showAddRegionDialog,
+  type,
+  title,
+  loading: dialogLoading,
+  handleAdd,
+  handleEdit,
+  handleSave,
+  formData,
+  formRef,
+} = useTableCrud(
+  {
+    name: '大区',
+    doCreate: add,
+    doUpdate: update,
+    refresh: refresh,
+    initForm: {
+      a: '',
+      b: '',
+      c: [],
+    },
+  },
+  formDialogRef
+);
+
+const fields = ref([
+  {
+    prop: 'a',
+    label: '服务单元名称',
+    type: 'select',
+    labelWidth: '100px',
+    colSpan: 5,
+  },
+  {
+    prop: 'b',
+    label: '大区经理',
+    type: 'select',
+    labelWidth: '100px',
+    colSpan: 5,
+  },
+  {
+    prop: 'c',
+    label: '区域',
+    type: 'select',
+    labelWidth: '100px',
+    colSpan: 5,
+  },
+  {
+    type: 'buttons',
+    colSpan: 2,
+    children: [
+      {
+        type: 'button',
+        text: '查询',
+      },
+    ],
+  },
+]);
+const params = reactive({
+  a: '',
+  b: '',
+  c: '',
+});
+</script>
+
+<style></style>

+ 71 - 0
src/views/service-unit-manage/service-unit/unit-manage/add-unit-dialog.vue

@@ -0,0 +1,71 @@
+<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-select v-model="formData.b"></t-select>
+      </t-form-item>
+      <t-form-item label="服务开始时间:">
+        <t-date-picker v-model="formData.c" />
+      </t-form-item>
+      <t-form-item label="服务截止时间:">
+        <t-date-picker v-model="formData.d" />
+      </t-form-item>
+      <t-form-item label="区域配比:">
+        <t-input-number
+          v-model="formData.e"
+          theme="column"
+          :decimalPlaces="0"
+          align="center"
+          :max="1000"
+          :min="0"
+          style="width: 80px"
+        ></t-input-number>
+        <span style="padding: 0 10px">:</span>
+        <t-input-number
+          v-model="formData.f"
+          theme="column"
+          :decimalPlaces="0"
+          align="center"
+          :max="1000"
+          :min="0"
+          style="width: 80px"
+        ></t-input-number>
+      </t-form-item>
+      <t-form-item label="负责人:">
+        <t-select v-model="formData.g"></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="AddUnitDialog">
+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>

+ 144 - 15
src/views/service-unit-manage/service-unit/unit-manage/index.vue

@@ -1,44 +1,173 @@
 <template>
   <div class="unit-manage flex flex-col">
     <SearchForm :fields="fields" :params="params"></SearchForm>
-    <div class="flex-1 page-wrap"> </div>
+    <div class="flex-1 page-wrap">
+      <div class="btn-group">
+        <t-button theme="success" @click="handleAdd">新增</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>
+
+    <AddUnitDialog
+      v-model:visible="showAddUnitDialog"
+      :title="title"
+      :type="type"
+      :handleSave="handleSave"
+      :formData="formData"
+      ref="formDialogRef"
+    ></AddUnitDialog>
   </div>
 </template>
 
 <script setup lang="jsx" name="UnitManage">
 import { ref, reactive } from 'vue';
+import { getTableData } from '@/api/test';
+import useFetchTable from '@/hooks/useFetchTable';
+import useTableCrud from '@/hooks/useTableCrud';
+import AddUnitDialog from './add-unit-dialog.vue';
+const formDialogRef = ref(null);
+const selectedRowKeys = ref([]);
+const selectChange = (value, { selectedRowData }) => {
+  selectedRowKeys.value = value;
+};
+
+const columns = [
+  { colKey: 'a', title: '服务单元名称', width: 140 },
+  { colKey: 'b', title: '服务开始时间', width: 140 },
+  { colKey: 'c', title: '服务截止时间', width: 140 },
+  { colKey: 'd', title: '业务类型', minWidth: 100 },
+  { 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 },
+  {
+    title: '操作',
+    colKey: 'operate',
+    fixed: 'right',
+    width: 260,
+    cell: (h, { row }) => {
+      return (
+        <div class="table-operations">
+          <t-link
+            theme="primary"
+            hover="color"
+            onClick={(e) => {
+              e.stopPropagation();
+              handleEdit(row);
+            }}
+          >
+            修改
+          </t-link>
+          <t-link theme="primary" hover="color">
+            作废
+          </t-link>
+          <t-link theme="primary" hover="color">
+            重启
+          </t-link>
+          <t-link theme="primary" hover="color">
+            关闭
+          </t-link>
+          <t-link theme="primary" hover="color">
+            设置考勤组
+          </t-link>
+        </div>
+      );
+    },
+  },
+];
+const {
+  loading: tableLoading,
+  pagination,
+  tableData,
+  fetchData,
+  onChange,
+} = useFetchTable(getTableData);
+
+const add = async () => {
+  await 1;
+  alert(1);
+};
+const update = async () => {};
+const refresh = async () => {};
+
+const {
+  visible: showAddUnitDialog,
+  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: '',
+    },
+  },
+  formDialogRef
+);
+
 const fields = ref([
   {
     prop: 'a',
     label: '业务类型',
     type: 'select',
-    labelWidth: '80px',
-    colSpan: 4,
+    labelWidth: '100px',
+    colSpan: 5,
   },
   {
     prop: 'b',
     label: '负责人',
     type: 'select',
-    labelWidth: '80px',
-    colSpan: 4,
+    labelWidth: '100px',
+    colSpan: 5,
   },
   {
     prop: 'c',
     label: '当前状态',
     type: 'select',
-    labelWidth: '80px',
-    colSpan: 4,
+    labelWidth: '100px',
+    colSpan: 5,
   },
   {
     prop: 'd',
     label: '创建时间',
-    type: 'select',
-    labelWidth: '80px',
-    colSpan: 4,
+    type: 'daterange',
+    labelWidth: '100px',
+    colSpan: 7,
   },
   {
     type: 'buttons',
-    colSpan: 3,
+    colSpan: 2,
     children: [
       {
         type: 'button',
@@ -48,17 +177,17 @@ const fields = ref([
   },
   {
     prop: 'e',
-    label: '创建时间',
+    label: '服务单元名称',
     labelWidth: '100px',
-    colSpan: 4,
+    colSpan: 5,
   },
 ]);
 const params = reactive({
   a: '',
   b: '',
   c: '',
-  d: '',
-  e: [],
+  d: [],
+  e: '',
 });
 </script>