Browse Source

静态页面开发

刘洋 1 year ago
parent
commit
10b5632d15

+ 1 - 0
components.d.ts

@@ -34,6 +34,7 @@ declare module 'vue' {
     TMenu: typeof import('tdesign-vue-next')['Menu']
     TMenuItem: typeof import('tdesign-vue-next')['MenuItem']
     TOption: typeof import('tdesign-vue-next')['Option']
+    TPopconfirm: typeof import('tdesign-vue-next')['Popconfirm']
     TSelect: typeof import('tdesign-vue-next')['Select']
     TSubmenu: typeof import('tdesign-vue-next')['Submenu']
     TTable: typeof import('tdesign-vue-next')['Table']

BIN
src/assets/imgs/bg.jpg


BIN
src/assets/imgs/loginbg.png


+ 24 - 21
src/layout/children-menu.vue

@@ -1,26 +1,29 @@
 <template>
   <template v-for="menu in modelValue" :key="menu.name">
-    <t-menu-item
-      v-if="!menu.children || menu.children.length === 0"
-      :value="menu.name"
-      @click="routerPush(menu)"
-    >
-      <template v-if="menu.meta.icon" #icon>
-        <t-icon :name="menu.meta.icon"></t-icon>
-      </template>
-      {{ menu.meta.title }}</t-menu-item
-    >
-    <t-submenu v-else :value="menu.name">
-      <template v-if="menu.meta.icon" #icon>
-        <t-icon :name="menu.meta.icon"></t-icon>
-      </template>
-      <template #title>
-        {{ menu.meta.title }}
-      </template>
-      <template v-if="menu.children">
-        <children-menu v-model="menu.children" />
-      </template>
-    </t-submenu>
+    <template v-if="menu.meta?.bind"> </template>
+    <template v-else>
+      <t-menu-item
+        v-if="!menu.children || menu.children.length === 0"
+        :value="menu.name"
+        @click="routerPush(menu)"
+      >
+        <template v-if="menu.meta.icon" #icon>
+          <t-icon :name="menu.meta.icon"></t-icon>
+        </template>
+        {{ menu.meta.title }}</t-menu-item
+      >
+      <t-submenu v-else :value="menu.name">
+        <template v-if="menu.meta.icon" #icon>
+          <t-icon :name="menu.meta.icon"></t-icon>
+        </template>
+        <template #title>
+          {{ menu.meta.title }}
+        </template>
+        <template v-if="menu.children">
+          <children-menu v-model="menu.children" />
+        </template>
+      </t-submenu>
+    </template>
   </template>
 </template>
 

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

@@ -15,7 +15,7 @@ export default {
       meta: {
         title: '派单管理',
         sort: 1,
-        icon: 'bulletpoint',
+        icon: 'user-talk',
       },
       children: [
         {
@@ -28,7 +28,6 @@ export default {
           meta: {
             title: '派单管理',
             sort: 1,
-            icon: 'bulletpoint',
           },
         },
       ],
@@ -40,7 +39,7 @@ export default {
       meta: {
         title: '服务单元管理',
         sort: 2,
-        icon: 'bulletpoint',
+        icon: 'server',
       },
       children: [
         {
@@ -53,7 +52,6 @@ export default {
           meta: {
             title: '服务单元管理',
             sort: 1,
-            icon: 'bulletpoint',
           },
         },
         {
@@ -66,7 +64,18 @@ export default {
           meta: {
             title: '服务范围管理',
             sort: 2,
-            icon: 'bulletpoint',
+          },
+        },
+        {
+          name: 'AddRange',
+          path: '/service-unit-manage/service-unit/add-range',
+          component: () =>
+            import(
+              '@/views/service-unit-manage/service-unit/add-range/index.vue'
+            ),
+          meta: {
+            title: '新增服务范围',
+            bind: 'RangeManage', //注意,这种不是菜单,但是也属于路由,比如name为"RangeManage"的时候,该路由也要有权限。需要在addRoute的时候考虑进去
           },
         },
         {
@@ -79,7 +88,6 @@ export default {
           meta: {
             title: '服务区域规划',
             sort: 3,
-            icon: 'bulletpoint',
           },
         },
       ],

+ 21 - 22
src/store/modules/user.js

@@ -33,39 +33,38 @@ const flatAsyncRoutes = (routes, breadcrumb = []) => {
 
 const views = import.meta.glob('../../views/**/**.vue');
 const empty = import.meta.glob('../../layout/empty.vue');
-const findRouterItemByName = (name, arr = asyncRoutes) => {
-  let find = null;
+const findRoutersItemByName = (name, arr = asyncRoutes, finds = []) => {
+  // arr = cloneDeep(arr);
   for (let i = 0; i < arr.length; i++) {
     const item = arr[i];
-    if (item.name === name) {
-      find = item;
-      break;
+    //asyncRoutes里,当有非菜单的路由时,其meta里会有bind字段定义,也要考虑进来
+    if (item.name === name || item.meta?.bind === name) {
+      finds.push(item);
     }
     if (item.children) {
-      find = findRouterItemByName(name, item.children);
-    }
-    if (find) {
-      break;
+      findRoutersItemByName(name, item.children, finds);
     }
   }
-  return find;
+  return finds;
 };
 // 菜单转换路由
 const filterAsyncRouter = (routerMap) => {
   const accessedRouters = [];
   routerMap.forEach((item) => {
-    const target = findRouterItemByName(item.name);
-    if (target) {
-      const route = {
-        path: target.path,
-        name: target.name,
-        // hidden: item.hidden == 1,
-        meta: target.meta,
-        children: item.children ? filterAsyncRouter(item.children) : null,
-        component: views[`../../views${target.path}/index.vue`],
-        redirect: target.redirect || null,
-      };
-      accessedRouters.push(route);
+    const targets = findRoutersItemByName(item.name);
+    if (targets.length) {
+      targets.forEach((target) => {
+        const route = {
+          path: target.path,
+          name: target.name,
+          // hidden: item.hidden == 1,
+          meta: target.meta,
+          children: item.children ? filterAsyncRouter(item.children) : null,
+          component: views[`../../views${target.path}/index.vue`],
+          redirect: target.redirect || null,
+        };
+        accessedRouters.push(route);
+      });
     }
   });
   return accessedRouters;

+ 6 - 2
src/style/global.less

@@ -4,9 +4,8 @@
 html,
 body {
   height: 100%;
-  background: #f5f7f9 url(../assets/imgs/bg.jpg) 0 0 no-repeat;
   background-size: cover;
-  font-size: 13px;
+  font-size: 14px;
   color: #333;
 }
 #app {
@@ -48,3 +47,8 @@ body {
     }
   }
 }
+.form-title {
+  line-height: 40px;
+  color: #333;
+  font-weight: bold;
+}

+ 46 - 129
src/views/login/index.vue

@@ -1,66 +1,48 @@
 <template>
   <div class="login flex justify-center items-center h-full">
     <div class="login-box">
-      <div class="left">
-        <div class="app-info">
-          <a href="http://www.qmth.com.cn" target="_blank"
-            >Copyright © 2021 启明泰和 v1.3.12 beta20230601</a
+      <t-form
+        ref="form"
+        :data="formData"
+        :label-width="0"
+        class="login-form"
+        :rules="rules"
+      >
+        <t-form-item name="a">
+          <t-input
+            v-model="formData.a"
+            clearable
+            placeholder="账号"
+            size="large"
           >
-          <br />
-          <a href="https://beian.miit.gov.cn/" target="_blank"
-            >鄂ICP备12000033号-3</a
-          >
-        </div>
-      </div>
-      <div class="right">
-        <router-view></router-view>
-        <template v-if="isLoginPage">
-          <h1>高校考试管理平台</h1>
+            <template #prefix-icon>
+              <desktop-icon />
+            </template>
+          </t-input>
+        </t-form-item>
 
-          <div class="tab-box">
-            <t-tabs v-model="loginMode" class="tabs">
-              <t-tab-panel value="admin" label="管理员登录"> </t-tab-panel>
-              <t-tab-panel value="mark" label="评卷员登录"> </t-tab-panel>
-            </t-tabs>
-          </div>
-          <t-form
-            ref="form"
-            :data="formData"
-            :label-width="0"
-            class="login-form"
-            :rules="rules"
+        <t-form-item name="b">
+          <t-input
+            v-model="formData.b"
+            type="password"
+            clearable
+            placeholder="密码"
+            size="large"
           >
-            <t-form-item name="a">
-              <t-input
-                v-model="formData.a"
-                clearable
-                placeholder="账号"
-                size="large"
-              >
-                <template #prefix-icon>
-                  <desktop-icon />
-                </template>
-              </t-input>
-            </t-form-item>
-
-            <t-form-item name="b">
-              <t-input
-                v-model="formData.b"
-                type="password"
-                clearable
-                placeholder="密码"
-                size="large"
-              >
-                <template #prefix-icon>
-                  <lock-on-icon />
-                </template>
-              </t-input>
-            </t-form-item>
-
-            <a class="submit-btn" @click="loginHandle">登 录</a>
-          </t-form>
-        </template>
-      </div>
+            <template #prefix-icon>
+              <lock-on-icon />
+            </template>
+          </t-input>
+        </t-form-item>
+      </t-form>
+      <t-button
+        block
+        class="m-t-30px"
+        @click="loginHandle"
+        size="large"
+        theme="success"
+        >登 录</t-button
+      >
     </div>
   </div>
   <!-- <button @click="loginHandle" class="m-t-10px">登录!</button> -->
@@ -77,13 +59,6 @@ const form = ref(null);
 
 const route = useRoute();
 const router = useRouter();
-const isLoginPage = computed(() => {
-  return route.name === 'Login';
-});
-const loginMode = ref('admin');
-const toggleMode = (m) => {
-  loginMode.value = m;
-};
 
 const formData = reactive({
   a: '',
@@ -99,14 +74,7 @@ const rules = {
 };
 
 const userStore = useUserStore();
-// const loginHandler = async () => {
-//   try {
-//     await userStore.login({});
-//     router.push(redirect);
-//   } catch (e) {
-//     console.log(e);
-//   }
-// };
+
 const loginHandle = () => {
   form.value.validate().then(async (result) => {
     const redirect = route.query.redirect
@@ -121,64 +89,13 @@ const loginHandle = () => {
 </script>
 <style lang="less" scoped>
 .login {
+  background: rgba(26, 188, 156, 1);
   .login-box {
-    width: 920px;
-    height: 520px;
-    background: rgba(255, 255, 255, 0.75);
-    box-shadow: 0px 15px 15px 0px rgba(203, 205, 211, 0.3);
-    .left {
-      width: 320px;
-      float: left;
-      height: 100%;
-      position: relative;
-      background: #142862 url(../../assets/imgs/loginbg.png) no-repeat 0 0;
-      .app-info {
-        position: absolute;
-        left: 0;
-        bottom: 40px;
-        padding: 0 38px;
-        a {
-          color: rgba(255, 255, 255, 0.65);
-          line-height: 1.5;
-        }
-      }
-    }
-    .right {
-      padding: 95px 130px;
-      margin-left: 320px;
-      height: 100%;
-      position: relative;
-      .submit-btn {
-        display: block;
-        width: 160px;
-        height: 54px;
-        text-align: center;
-        line-height: 54px;
-        border-radius: 26px;
-        background-image: linear-gradient(to right, #88d3fc, #66ade8);
-        margin: 40px auto 0 auto;
-        font-size: 20px;
-        color: #fff;
-        font-weight: 700;
-        cursor: pointer;
-      }
-      .login-form {
-        margin-top: 30px;
-      }
-      & > h1 {
-        font-size: 23px;
-        text-align: center;
-      }
-      .tab-box {
-        margin-top: 30px;
-        width: 204px;
-        margin-left: auto;
-        margin-right: auto;
-        .t-tabs {
-          background-color: transparent !important;
-        }
-      }
-    }
+    width: 350px;
+    background: #fff;
+    box-shadow: rgba(0, 0, 0, 0.35) 0px 0px 10px;
+    border-radius: 10px;
+    padding: 24px;
   }
 }
 </style>

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

@@ -58,7 +58,6 @@ const formRef = ref(null);
 const props = defineProps({
   visible: Boolean,
   title: String,
-  type: String,
   handleSave: Function,
   formData: Object,
 });

+ 41 - 0
src/views/service-unit-manage/dispatch/dispatch-manage/delineation-dialog.vue

@@ -0,0 +1,41 @@
+// 划定 弹框
+<template>
+  <my-dialog
+    :visible="visible"
+    @close="emit('update:visible', false)"
+    header="划定"
+    :width="600"
+    labelWidth="140px"
+    :closeOnOverlayClick="false"
+  >
+    <div class="form-title">派单信息</div>
+    <t-form ref="formRef" :model="formData">
+      <t-form-item label="服务单元名称">
+        <t-select v-model="formData.a"></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="save">保存</t-button>
+    </template>
+  </my-dialog>
+</template>
+<script setup name="DelineationDialog">
+import { ref, reactive } from 'vue';
+const emit = defineEmits(['update:visible', 'success']);
+const formRef = ref(null);
+
+const props = defineProps({
+  visible: Boolean,
+  title: String,
+});
+const formData = reactive({
+  a: 1,
+});
+const save = () => {
+  //ajax...
+  emit('success');
+};
+</script>

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

@@ -5,7 +5,9 @@
       <div class="btn-group">
         <t-button theme="success" @click="handleAdd">新增</t-button>
         <t-button theme="success">作废</t-button>
-        <t-button theme="success">批量划定</t-button>
+        <t-button theme="success" @click="multDelineationHandle"
+          >批量划定</t-button
+        >
       </div>
       <t-table
         size="small"
@@ -34,6 +36,16 @@
       :formData="formData"
       ref="formDialogRef"
     ></AddDispatchDialog>
+    <DelineationDialog
+      v-model:visible="showDelineationDialog"
+      :rowData="rowData"
+    >
+    </DelineationDialog>
+    <MultDelineationDialog
+      v-model:visible="showMultDelineationDialog"
+      :selectedRowKeys="selectedRowKeys"
+    >
+    </MultDelineationDialog>
   </div>
 </template>
 
@@ -44,12 +56,28 @@ import { getTableData } from '@/api/test';
 import useFetchTable from '@/hooks/useFetchTable';
 import useTableCrud from '@/hooks/useTableCrud';
 import AddDispatchDialog from './add-dispatch-dialog.vue';
+import DelineationDialog from './delineation-dialog.vue';
+import MultDelineationDialog from './mult-delineation-dialog.vue';
 
+const showDelineationDialog = ref(false);
+const showMultDelineationDialog = ref(false);
 const formDialogRef = ref(null);
 const selectedRowKeys = ref([]);
 const selectChange = (value, { selectedRowData }) => {
   selectedRowKeys.value = value;
 };
+const multDelineationHandle = () => {
+  if (!selectedRowKeys.value.length) {
+    //...警告语
+  } else {
+    showMultDelineationDialog.value = true;
+  }
+};
+const rowData = ref({});
+const handleDelineation = (row) => {
+  rowData.value = row;
+  showDelineationDialog.value = true;
+};
 const columns = [
   {
     colKey: 'row-select',
@@ -78,7 +106,14 @@ const columns = [
     cell: (h, { row }) => {
       return (
         <div class="table-operations">
-          <t-link theme="primary" hover="color">
+          <t-link
+            theme="primary"
+            hover="color"
+            onClick={(e) => {
+              e.stopPropagation();
+              handleDelineation(row);
+            }}
+          >
             划定
           </t-link>
           <t-link
@@ -91,7 +126,14 @@ const columns = [
           >
             修改
           </t-link>
-          <t-link theme="primary" hover="color">
+          <t-link
+            theme="primary"
+            hover="color"
+            onClick={(e) => {
+              e.stopPropagation();
+              handleDelineation(row);
+            }}
+          >
             重新划定
           </t-link>
         </div>

+ 41 - 0
src/views/service-unit-manage/dispatch/dispatch-manage/mult-delineation-dialog.vue

@@ -0,0 +1,41 @@
+// 批量划定 弹框
+<template>
+  <my-dialog
+    :visible="visible"
+    @close="emit('update:visible', false)"
+    header="批量划定"
+    :width="500"
+    labelWidth="140px"
+    :closeOnOverlayClick="false"
+  >
+    <t-form ref="formRef" :model="formData">
+      <t-form-item label="服务单元名称">
+        <t-select v-model="formData.a"></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="save">保存</t-button>
+    </template>
+  </my-dialog>
+</template>
+<script setup name="MultDelineationDialog">
+import { ref, reactive } from 'vue';
+const emit = defineEmits(['update:visible', 'success']);
+const formRef = ref(null);
+
+const props = defineProps({
+  visible: Boolean,
+  title: String,
+  selectedRowKeys: Array,
+});
+const formData = reactive({
+  a: 1,
+});
+const save = () => {
+  //ajax...
+  emit('success');
+};
+</script>

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

@@ -0,0 +1,142 @@
+<template>
+  <div class="add-range flex flex-col">
+    <SearchForm :fields="fields" :params="params"></SearchForm>
+
+    <div class="flex-1 page-wrap">
+      <div class="btn-group">
+        <t-button theme="success" @click="regionalHandle">批量划定</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>
+  </div>
+</template>
+
+<script setup name="AddRange">
+import { reactive, ref } from 'vue';
+import { getTableData } from '@/api/test';
+import useFetchTable from '@/hooks/useFetchTable';
+
+const selectedRowKeys = ref([]);
+const selectChange = (value, { selectedRowData }) => {
+  selectedRowKeys.value = value;
+};
+const regionalHandle = () => {
+  if (!selectedRowKeys.value.length) {
+    //...警告语
+  } else {
+  }
+};
+const columns = [
+  {
+    colKey: 'row-select',
+    type: 'multiple',
+    width: 50,
+    fixed: 'left',
+  },
+  { colKey: 'a', title: '项目单号', minWidth: 80 },
+  { colKey: 'b', title: '派单时间', width: 140 },
+  { colKey: 'c', title: '派单人', minWidth: 80 },
+  { colKey: 'd', title: '客户类型', minWidth: 80 },
+  { colKey: 'e', title: '客户名称', minWidth: 80 },
+  { colKey: 'f', title: '项目名称', minWidth: 80 },
+  { colKey: 'g', title: '实施产品', minWidth: 80 },
+  { colKey: 'h', title: '考试开始时间', width: 140 },
+  { colKey: 'i', title: '考试结束时间', width: 140 },
+  { colKey: 'j', title: '大区经理', minWidth: 80 },
+  { colKey: 'k', title: '提交人', minWidth: 80 },
+  { colKey: 'l', title: '提交时间', width: 140 },
+];
+const {
+  loading: tableLoading,
+  pagination,
+  tableData,
+  fetchData,
+  onChange,
+} = useFetchTable(getTableData);
+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: 2,
+    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: [],
+});
+</script>
+
+<style></style>

+ 22 - 5
src/views/service-unit-manage/service-unit/range-manage/index.vue

@@ -3,7 +3,9 @@
     <SearchForm :fields="fields" :params="params"></SearchForm>
     <div class="flex-1 page-wrap">
       <div class="btn-group">
-        <t-button theme="success">新增服务范围</t-button>
+        <t-button theme="success" @click="addServiceRange"
+          >新增服务范围</t-button
+        >
       </div>
       <t-table
         size="small"
@@ -27,7 +29,11 @@
 import { ref, reactive } from 'vue';
 import { getTableData } from '@/api/test';
 import useFetchTable from '@/hooks/useFetchTable';
-
+import { useRouter } from 'vue-router';
+const router = useRouter();
+const addServiceRange = () => {
+  router.push({ name: 'AddRange' });
+};
 const columns = [
   { colKey: 'a', title: '项目单号', width: 120 },
   { colKey: 'b', title: '客户名称', minWidth: 100 },
@@ -45,9 +51,17 @@ const columns = [
     cell: (h, { row }) => {
       return (
         <div class="table-operations">
-          <t-link theme="primary" hover="color">
-            移除
-          </t-link>
+          <t-popconfirm
+            onConfirm={() => {
+              deleteRow(row);
+            }}
+            theme="warning"
+            content="您确定要将当前派单从派单服务单元中移除吗?"
+          >
+            <t-link theme="primary" hover="color">
+              移除
+            </t-link>
+          </t-popconfirm>
         </div>
       );
     },
@@ -62,6 +76,9 @@ const {
 } = useFetchTable(getTableData);
 
 const refresh = async () => {};
+const deleteRow = (row) => {
+  console.log('deleteRow');
+};
 
 const fields = ref([
   {

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

@@ -75,7 +75,6 @@ const onChange = (newTargetValue) => {
 const props = defineProps({
   visible: Boolean,
   title: String,
-  type: String,
   handleSave: Function,
   formData: Object,
 });

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

@@ -61,7 +61,6 @@ const formRef = ref(null);
 const props = defineProps({
   visible: Boolean,
   title: String,
-  type: String,
   handleSave: Function,
   formData: Object,
 });

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

@@ -17,9 +17,6 @@
           onChange,
           total: pagination.total,
         }"
-        :selected-row-keys="selectedRowKeys"
-        select-on-row-click
-        @select-change="selectChange"
       >
       </t-table>
     </div>
@@ -42,10 +39,6 @@ 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 },