Browse Source

修改菜单

zs 1 year ago
parent
commit
ba674a08a3

+ 23 - 3
src/assets/icon/iconfont.css

@@ -1,8 +1,8 @@
 @font-face {
   font-family: "iconfont"; /* Project id 4293191 */
-  src: url('iconfont.woff2?t=1697681511893') format('woff2'),
-       url('iconfont.woff?t=1697681511893') format('woff'),
-       url('iconfont.ttf?t=1697681511893') format('truetype');
+  src: url('iconfont.woff2?t=1697767042230') format('woff2'),
+       url('iconfont.woff?t=1697767042230') format('woff'),
+       url('iconfont.ttf?t=1697767042230') format('truetype');
 }
 
 .iconfont {
@@ -13,6 +13,26 @@
   -moz-osx-font-smoothing: grayscale;
 }
 
+.icon-icon-person-hushi:before {
+  content: "\e606";
+}
+
+.icon-tubiao_-:before {
+  content: "\e6fe";
+}
+
+.icon-guanggaoguanli:before {
+  content: "\e602";
+}
+
+.icon-yishengguanli:before {
+  content: "\e605";
+}
+
+.icon--_bingren:before {
+  content: "\e62b";
+}
+
 .icon-qunzu:before {
   content: "\e656";
 }

File diff suppressed because it is too large
+ 1 - 1
src/assets/icon/iconfont.js


+ 35 - 0
src/assets/icon/iconfont.json

@@ -5,6 +5,41 @@
   "css_prefix_text": "icon-",
   "description": "",
   "glyphs": [
+    {
+      "icon_id": "31850940",
+      "name": "icon-person-hushi",
+      "font_class": "icon-person-hushi",
+      "unicode": "e606",
+      "unicode_decimal": 58886
+    },
+    {
+      "icon_id": "11190337",
+      "name": "报告",
+      "font_class": "tubiao_-",
+      "unicode": "e6fe",
+      "unicode_decimal": 59134
+    },
+    {
+      "icon_id": "19657694",
+      "name": "广告管理",
+      "font_class": "guanggaoguanli",
+      "unicode": "e602",
+      "unicode_decimal": 58882
+    },
+    {
+      "icon_id": "5427090",
+      "name": "医生管理",
+      "font_class": "yishengguanli",
+      "unicode": "e605",
+      "unicode_decimal": 58885
+    },
+    {
+      "icon_id": "14015750",
+      "name": "-_病人1",
+      "font_class": "-_bingren",
+      "unicode": "e62b",
+      "unicode_decimal": 58923
+    },
     {
       "icon_id": "657588",
       "name": "群组",

BIN
src/assets/icon/iconfont.ttf


BIN
src/assets/icon/iconfont.woff


BIN
src/assets/icon/iconfont.woff2


+ 2 - 0
src/components/admin-frame/parts/Sidebar.vue

@@ -68,6 +68,7 @@ const route = useRoute();
 let onRoutes = route.path;
 let user: Ref<any> = ref({});
 const styleInfo: Ref<any> = ref(menuInfo.info);
+const menuList: Ref<any> = ref(menuInfo.menuList);
 let items: Ref<any> = ref([]);
 onMounted(async () => {
   user.value = store.state.user;
@@ -76,6 +77,7 @@ onMounted(async () => {
 const getMenu = async () => {
   let res: IQueryResult = await roleAxios.um();
   if (res.errcode == 0) items.value = res.data;
+  items.value = menuList.value;
 };
 
 watch(

+ 33 - 1
src/layout/site.ts

@@ -10,5 +10,37 @@ export const menuInfo = {
     mode: 'horizontal',
     backColor: '#242f42',
     textColor: '#ffffff'
-  }
+  },
+  // 菜单
+  menuList: [
+    { icon: 'icon-yonghu', _id: 'admin_1', path: '/homeIndex', name: '系统首页' },
+    {
+      icon: 'icon-shezhi',
+      _id: 'admin_2',
+      name: '系统设置',
+      index: '2',
+      type: '0',
+      children: [
+        { icon: 'icon-shezhi', _id: 'admin_2_1', path: '/system/config', name: '基础设置' },
+        { icon: 'icon-shezhi', _id: 'admin_2_2', path: '/system/menus', name: '菜单设置' },
+        { icon: 'icon-shezhi', _id: 'admin_2_3', path: '/system/role', name: '角色设置' }
+      ]
+    },
+    { icon: 'icon-yishengguanli', _id: 'admin_3', path: '/doctor', name: '医生管理' },
+    { icon: 'icon--_bingren', _id: 'admin_4', path: '/patient', name: '病人管理' },
+    { icon: 'icon-qunzu', _id: 'admin_5', path: '/group', name: '群组管理' },
+    { icon: 'icon-tubiao_-', _id: 'admin_6', path: '/article', name: '医疗科普管理' },
+    { icon: 'icon-guanggaoguanli', _id: 'admin_7', path: '/advert', name: '广告管理' },
+    {
+      icon: 'icon-yonghuxinxi',
+      _id: 'admin_8',
+      name: '账号管理',
+      index: '8',
+      type: '0',
+      children: [
+        { icon: 'icon-yonghuxinxi', _id: 'admin_8_1', path: '/acccount/information', name: '账号信息' },
+        { icon: 'icon-yonghuxinxi', _id: 'admin_8_1', path: '/acccount/updatepd', name: '修改密码' }
+      ]
+    }
+  ]
 };

+ 32 - 7
src/router/index.ts

@@ -24,6 +24,11 @@ const router = createRouter({
           meta: { title: '系统首页' },
           component: () => import('@/views/home/index.vue')
         },
+        {
+          path: '/system/config',
+          meta: { title: '基础设置' },
+          component: () => import('@/views/system/config/index.vue')
+        },
         {
           path: '/system/role',
           meta: { title: '角色管理' },
@@ -40,14 +45,34 @@ const router = createRouter({
           component: () => import('@/views/system/menus/index.vue')
         },
         {
-          path: '/system/dict',
-          meta: { title: '字典管理' },
-          component: () => import('@/views/system/dict/index.vue')
+          path: '/doctor',
+          meta: { title: '医生管理' },
+          component: () => import('@/views/doctor/index.vue')
+        },
+        {
+          path: '/nurse',
+          meta: { title: '护士管理' },
+          component: () => import('@/views/nurse/index.vue')
+        },
+        {
+          path: '/patient',
+          meta: { title: '病人管理' },
+          component: () => import('@/views/patient/index.vue')
+        },
+        {
+          path: '/group',
+          meta: { title: '群组管理' },
+          component: () => import('@/views/group/index.vue')
+        },
+        {
+          path: '/article',
+          meta: { title: '医疗科普管理' },
+          component: () => import('@/views/article/index.vue')
         },
         {
-          path: '/system/dictData',
-          meta: { title: '字典数据管理' },
-          component: () => import('@/views/system/dictData/index.vue')
+          path: '/advert',
+          meta: { title: '广告管理' },
+          component: () => import('@/views/advert/index.vue')
         },
         {
           path: '/acccount/information',
@@ -70,7 +95,7 @@ router.beforeEach(async (to, from, next) => {
     if (token) {
       const res = await axios.request({
         method: 'get',
-        url: '/visit/tool/token',
+        url: '/visit/login/analysis',
         responseType: 'json',
         headers: {
           token: token

+ 52 - 0
src/stores/basic/config.ts

@@ -0,0 +1,52 @@
+import { ref, computed } from 'vue';
+import { defineStore } from 'pinia';
+import { AxiosWrapper } from '@/util/axios-wrapper';
+import _ from 'lodash';
+
+import type { IQueryType, IQueryResult, IQueryParams } from '@/util/types.util';
+const axios = new AxiosWrapper();
+const api = {
+  url: `/visit/config`
+};
+export const ConfigStore = defineStore('config', () => {
+  const count = ref(0);
+  const doubleCount = computed(() => count.value * 2);
+  function increment() {
+    count.value++;
+  }
+  const query = async ({ skip = 0, limit = undefined, ...info }: IQueryParams = {}): Promise<IQueryResult> => {
+    let cond: IQueryType = {};
+    if (skip) cond.skip = skip;
+    if (limit) cond.limit = limit;
+    cond = { ...cond, ...info };
+    const res = await axios.$get(`${api.url}`, cond);
+    return res;
+  };
+  const fetch = async (payload: any): Promise<IQueryResult> => {
+    const res = await axios.$get(`${api.url}/${payload}`);
+    return res;
+  };
+  const create = async (payload: any): Promise<IQueryResult> => {
+    const res = await axios.$post(`${api.url}`, payload);
+    return res;
+  };
+  const update = async (payload: any): Promise<IQueryResult> => {
+    const id = _.get(payload, 'id', _.get(payload, '_id'));
+    const res = await axios.$post(`${api.url}/${id}`, payload);
+    return res;
+  };
+  const del = async (payload: any): Promise<IQueryResult> => {
+    const res = await axios.$delete(`${api.url}/${payload}`);
+    return res;
+  };
+  return {
+    count,
+    doubleCount,
+    increment,
+    query,
+    fetch,
+    create,
+    update,
+    del
+  };
+});

+ 18 - 3
src/stores/users/login.ts

@@ -31,8 +31,20 @@ export const LoginStore = defineStore('login', () => {
     return res;
   };
   //password
-  const rp = async (payload: any): Promise<IQueryResult> => {
-    const res = await axios.$post(`${api.url}/rp`, payload);
+  const adminRp = async (payload: any): Promise<IQueryResult> => {
+    const res = await axios.$post(`${api.url}/updatePwd/Admin`, payload);
+    return res;
+  };
+  const doctorRp = async (payload: any): Promise<IQueryResult> => {
+    const res = await axios.$post(`${api.url}/updatePwd/Doctor`, payload);
+    return res;
+  };
+  const nurseRp = async (payload: any): Promise<IQueryResult> => {
+    const res = await axios.$post(`${api.url}/updatePwd/Nurse`, payload);
+    return res;
+  };
+  const patientRp = async (payload: any): Promise<IQueryResult> => {
+    const res = await axios.$post(`${api.url}/updatePwd/Patient`, payload);
     return res;
   };
   return {
@@ -43,6 +55,9 @@ export const LoginStore = defineStore('login', () => {
     doctor,
     nurse,
     patient,
-    rp
+    adminRp,
+    doctorRp,
+    nurseRp,
+    patientRp
   };
 });

+ 52 - 0
src/stores/users/patient.ts

@@ -0,0 +1,52 @@
+import { ref, computed } from 'vue';
+import { defineStore } from 'pinia';
+import { AxiosWrapper } from '@/util/axios-wrapper';
+import _ from 'lodash';
+
+import type { IQueryType, IQueryResult, IQueryParams } from '@/util/types.util';
+const axios = new AxiosWrapper();
+const api = {
+  url: `/visit/patient`
+};
+export const PatientStore = defineStore('patient', () => {
+  const count = ref(0);
+  const doubleCount = computed(() => count.value * 2);
+  function increment() {
+    count.value++;
+  }
+  const query = async ({ skip = 0, limit = undefined, ...info }: IQueryParams = {}): Promise<IQueryResult> => {
+    let cond: IQueryType = {};
+    if (skip) cond.skip = skip;
+    if (limit) cond.limit = limit;
+    cond = { ...cond, ...info };
+    const res = await axios.$get(`${api.url}`, cond);
+    return res;
+  };
+  const fetch = async (payload: any): Promise<IQueryResult> => {
+    const res = await axios.$get(`${api.url}/${payload}`);
+    return res;
+  };
+  const create = async (payload: any): Promise<IQueryResult> => {
+    const res = await axios.$post(`${api.url}`, payload);
+    return res;
+  };
+  const update = async (payload: any): Promise<IQueryResult> => {
+    const id = _.get(payload, 'id', _.get(payload, '_id'));
+    const res = await axios.$post(`${api.url}/${id}`, payload);
+    return res;
+  };
+  const del = async (payload: any): Promise<IQueryResult> => {
+    const res = await axios.$delete(`${api.url}/${payload}`);
+    return res;
+  };
+  return {
+    count,
+    doubleCount,
+    increment,
+    query,
+    fetch,
+    create,
+    update,
+    del
+  };
+});

+ 41 - 0
src/views/acccount/index.vue

@@ -0,0 +1,41 @@
+<template>
+  <div id="index">
+    <el-row>
+      <el-col :span="24" class="main animate__animated animate__backInRight" v-loading="loading">
+        <el-col :span="24" class="one"> 系统首页 </el-col>
+      </el-col>
+    </el-row>
+  </div>
+</template>
+
+<script setup lang="ts">
+// 基础
+import type { Ref } from 'vue';
+import { onMounted, ref } from 'vue';
+
+// 接口
+// import { ToolsStore } from '@/stores/tool';
+// import type { IQueryResult } from '@/util/types.util';
+// const toolsAxios = ToolsStore();
+
+// 加载中
+const loading: Ref<any> = ref(false);
+
+// 请求
+onMounted(async () => {
+  loading.value = true;
+  search();
+  loading.value = false;
+});
+const search = async () => {
+  // let res: IQueryResult = await toolsAxios.dataCount();
+  // if (res.errcode == '0') {
+  //   info.value = res.data;
+  // }
+};
+</script>
+<style scoped lang="scss">
+.main {
+  padding: 2px;
+}
+</style>

+ 0 - 6
src/views/acccount/information/index.vue

@@ -26,12 +26,10 @@ import { AdminStore } from '@/stores/users/admin'; // 管理员
 import { DoctorStore } from '@/stores/users/doctor'; //医生
 import { NurseStore } from '@/stores/users/nurse'; //护士
 import { RoleStore } from '@/stores/basic/role'; // 角色
-import { DictDataStore } from '@/stores/basic/dictData'; // 字典表
 import type { IQueryResult } from '@/util/types.util';
 const adminAxios = AdminStore();
 const doctorAxios = DoctorStore();
 const nurseAxios = NurseStore();
-const dictAxios = DictDataStore();
 const roleAxios = RoleStore();
 let user: Ref<any> = ref(store.state.user);
 // 加载中
@@ -51,7 +49,6 @@ const rules = reactive<FormRules>({
 });
 // 字典表
 const roleList: Ref<any> = ref([]);
-const statusList: Ref<any> = ref([]);
 // 请求
 onMounted(async () => {
   loading.value = true;
@@ -82,9 +79,6 @@ const searchOther = async () => {
   // 角色
   res = await roleAxios.query({ is_use: '0' });
   if (res.errcode == '0') roleList.value = res.data;
-  // 状态
-  res = await dictAxios.query({ type: 'exam_status', is_use: '0' });
-  if (res.errcode == '0') statusList.value = res.data;
 };
 // 返回上一页
 const toBack = () => {

+ 5 - 9
src/views/acccount/updatepd/index.vue

@@ -18,13 +18,9 @@ import { onMounted, ref } from 'vue';
 import { ElMessage } from 'element-plus';
 import { useRouter } from 'vue-router';
 // 接口
-import { AdminStore } from '@/stores/users/admin'; // 管理员
-import { DoctorStore } from '@/stores/users/doctor'; //医生
-import { NurseStore } from '@/stores/users/nurse'; //护士
+import { LoginStore } from '@/stores/users/login'; // 修改密码
 import type { IQueryResult } from '@/util/types.util';
-const adminAxios = AdminStore();
-const doctorAxios = DoctorStore();
-const nurseAxios = NurseStore();
+const loginAxios = LoginStore();
 // 加载中
 const loading: Ref<any> = ref(false);
 // 路由
@@ -60,9 +56,9 @@ onMounted(async () => {
 const toSave = async (data: any) => {
   let user: any = store.state.user;
   let res: IQueryResult;
-  if (user.type == '0') await adminAxios.rp({ _id: user._id, password: data.password }); //管理员
-  else if (user.type == '1') await doctorAxios.rp({ _id: user._id, password: data.password }); //医生
-  else res = await nurseAxios.rp({ _id: user._id, password: data.password }); //护士
+  if (user.type == '0') await loginAxios.adminRp({ _id: user._id, password: data.password }); //管理员
+  else if (user.type == '1') await loginAxios.doctorRp({ _id: user._id, password: data.password }); //医生
+  else res = await loginAxios.nurseRp({ _id: user._id, password: data.password }); //护士
   if (res.errcode == '0') {
     ElMessage({ type: 'success', message: '修改密码成功' });
     // 退出登录

+ 41 - 0
src/views/advert/index.vue

@@ -0,0 +1,41 @@
+<template>
+  <div id="index">
+    <el-row>
+      <el-col :span="24" class="main animate__animated animate__backInRight" v-loading="loading">
+        <el-col :span="24" class="one"> 系统首页 </el-col>
+      </el-col>
+    </el-row>
+  </div>
+</template>
+
+<script setup lang="ts">
+// 基础
+import type { Ref } from 'vue';
+import { onMounted, ref } from 'vue';
+
+// 接口
+// import { ToolsStore } from '@/stores/tool';
+// import type { IQueryResult } from '@/util/types.util';
+// const toolsAxios = ToolsStore();
+
+// 加载中
+const loading: Ref<any> = ref(false);
+
+// 请求
+onMounted(async () => {
+  loading.value = true;
+  search();
+  loading.value = false;
+});
+const search = async () => {
+  // let res: IQueryResult = await toolsAxios.dataCount();
+  // if (res.errcode == '0') {
+  //   info.value = res.data;
+  // }
+};
+</script>
+<style scoped lang="scss">
+.main {
+  padding: 2px;
+}
+</style>

+ 41 - 0
src/views/article/index.vue

@@ -0,0 +1,41 @@
+<template>
+  <div id="index">
+    <el-row>
+      <el-col :span="24" class="main animate__animated animate__backInRight" v-loading="loading">
+        <el-col :span="24" class="one"> 系统首页 </el-col>
+      </el-col>
+    </el-row>
+  </div>
+</template>
+
+<script setup lang="ts">
+// 基础
+import type { Ref } from 'vue';
+import { onMounted, ref } from 'vue';
+
+// 接口
+// import { ToolsStore } from '@/stores/tool';
+// import type { IQueryResult } from '@/util/types.util';
+// const toolsAxios = ToolsStore();
+
+// 加载中
+const loading: Ref<any> = ref(false);
+
+// 请求
+onMounted(async () => {
+  loading.value = true;
+  search();
+  loading.value = false;
+});
+const search = async () => {
+  // let res: IQueryResult = await toolsAxios.dataCount();
+  // if (res.errcode == '0') {
+  //   info.value = res.data;
+  // }
+};
+</script>
+<style scoped lang="scss">
+.main {
+  padding: 2px;
+}
+</style>

+ 161 - 0
src/views/doctor/index.vue

@@ -0,0 +1,161 @@
+<template>
+  <div id="index">
+    <el-row>
+      <el-col :span="24" class="main animate__animated animate__backInRight" v-loading="loading">
+        <el-col :span="24" class="one">
+          <cSearch :is_title="false" :is_search="true" :fields="fields" @search="toSearch"> </cSearch>
+        </el-col>
+        <el-col :span="24" class="two">
+          <cButton @toAdd="toAdd()"> </cButton>
+        </el-col>
+        <el-col :span="24" class="thr">
+          <cTable :fields="fields" :opera="opera" :list="list" @query="search" :total="total" @edit="toEdit" @del="toDel"></cTable>
+        </el-col>
+      </el-col>
+    </el-row>
+    <cDialog :dialog="dialog" @toClose="toClose">
+      <template v-slot:info>
+        <el-col :span="24" class="dialog_one" v-if="dialog.type == '1'">
+          <cForm :span="24" :fields="formFields" :form="form" :rules="rules" @save="toSave" label-width="auto">
+            <template #icon>
+              <cUpload
+                :model="`${'icon'}`"
+                :limit="1"
+                listType="picture-card"
+                url="/visit/api/files/follow/doctor/upload"
+                accept="*"
+                :list="form.icon"
+                @change="onUpload"
+              ></cUpload>
+            </template>
+          </cForm>
+        </el-col>
+      </template>
+    </cDialog>
+  </div>
+</template>
+
+<script setup lang="ts">
+// 基础
+import type { FormRules } from 'element-plus';
+import type { Ref } from 'vue';
+import { ref, onMounted, getCurrentInstance, reactive } from 'vue';
+import { ElMessage } from 'element-plus';
+// 接口
+import { DoctorStore } from '@/stores/users/doctor';
+import type { IQueryResult } from '@/util/types.util';
+const doctorAxios = DoctorStore();
+const { proxy } = getCurrentInstance() as any;
+// 加载中
+const loading: Ref<any> = ref(false);
+let list: Ref<any> = ref([]);
+let total: Ref<number> = ref(0);
+let skip = 0;
+let limit: number = proxy.$limit;
+let fields: Ref<any[]> = ref([
+  { label: '账号', model: 'account', isSearch: true },
+  { label: '姓名', model: 'name', isSearch: true },
+  { label: '手机号', model: 'mobile', isSearch: true },
+  { label: '医院名称', model: 'hos_name', isSearch: true },
+  { label: '科室名称', model: 'dept_name', isSearch: true },
+  { label: '职务', model: 'title', isSearch: true },
+  { label: '职称', model: 'post', isSearch: true }
+]);
+// 操作
+let opera: Ref<any[]> = ref([
+  { label: '修改', method: 'edit' },
+  { label: '删除', method: 'del', confirm: true, type: 'danger' }
+]);
+// 查询数据
+let searchForm: Ref<any> = ref({});
+// 弹框
+const dialog: Ref<any> = ref({ title: '信息管理', show: false, type: '1' });
+const form: Ref<any> = ref({ icon: [] });
+const formFields: Ref<any> = ref([
+  { label: '账号', model: 'account' },
+  { label: '密码', model: 'password', type: 'password' },
+  { label: '姓名', model: 'name' },
+  { label: '头像', model: 'icon', custom: true },
+  { label: '手机号', model: 'mobile' },
+  { label: '医院名称', model: 'hos_name' },
+  { label: '科室名称', model: 'dept_name' },
+  { label: '职务', model: 'title' },
+  { label: '职称', model: 'post' },
+  { label: '简介', model: 'content', type: 'textarea' }
+]);
+const rules = reactive<FormRules>({
+  account: [{ required: true, message: '请输入账号', trigger: 'blur' }],
+  password: [{ required: true, message: '请输入密码', trigger: 'blur' }],
+  name: [{ required: true, message: '请输入姓名', trigger: 'blur' }],
+  mobile: [{ required: true, message: '请输入手机号', trigger: 'blur' }],
+  hos_name: [{ required: true, message: '请输入医院名称', trigger: 'blur' }],
+  dept_name: [{ required: true, message: '请输入科室名称', trigger: 'blur' }],
+  title: [{ required: true, message: '请输入职务', trigger: 'blur' }],
+  post: [{ required: true, message: '请输入职称', trigger: 'blur' }]
+});
+// 请求
+onMounted(async () => {
+  loading.value = true;
+  await search({ skip, limit });
+  loading.value = false;
+});
+const search = async (e: { skip: number; limit: number }) => {
+  const info = { skip: e.skip, limit: e.limit, ...searchForm.value };
+  const res: IQueryResult = await doctorAxios.query(info);
+  if (res.errcode == '0') {
+    list.value = res.data;
+    total.value = res.total;
+  }
+};
+const toSearch = (query: any) => {
+  searchForm.value = query;
+  search({ skip, limit });
+};
+const onUpload = (e: { model: string; value: Array<[]> }) => {
+  const { model, value } = e;
+  form.value[model] = value;
+};
+// 提交保存
+const toSave = async (data: any) => {
+  let res: IQueryResult;
+  if (data._id) res = await doctorAxios.update(data);
+  else res = await doctorAxios.create(data);
+  if (res.errcode == 0) {
+    ElMessage({ type: `success`, message: `维护信息成功` });
+    toClose();
+  }
+};
+// 新增
+const toAdd = () => {
+  dialog.value = { title: '信息管理', show: true, type: '1' };
+};
+// 修改
+const toEdit = async (data: any) => {
+  let res: IQueryResult = await doctorAxios.fetch(data._id);
+  if (res.errcode == '0') {
+    form.value = res.data;
+    dialog.value = { title: '信息管理', show: true, type: '1' };
+  }
+};
+// 删除
+const toDel = async (data: any) => {
+  let res: IQueryResult = await doctorAxios.del(data._id);
+  if (res.errcode == 0) {
+    ElMessage({ type: `success`, message: `刪除信息成功` });
+    search({ skip, limit });
+  }
+};
+// 关闭弹框
+const toClose = () => {
+  form.value = { icon: [] };
+  dialog.value = { show: false };
+  search({ skip, limit });
+};
+</script>
+<style scoped lang="scss">
+.main {
+  .two {
+    margin: 0 0 10px 0;
+  }
+}
+</style>

+ 161 - 0
src/views/group/index.vue

@@ -0,0 +1,161 @@
+<template>
+  <div id="index">
+    <el-row>
+      <el-col :span="24" class="main animate__animated animate__backInRight" v-loading="loading">
+        <el-col :span="24" class="one">
+          <cSearch :is_title="false" :is_search="true" :fields="fields" @search="toSearch"> </cSearch>
+        </el-col>
+        <el-col :span="24" class="two">
+          <cButton @toAdd="toAdd()"> </cButton>
+        </el-col>
+        <el-col :span="24" class="thr">
+          <cTable :fields="fields" :opera="opera" :list="list" @query="search" :total="total" @edit="toEdit" @del="toDel"></cTable>
+        </el-col>
+      </el-col>
+    </el-row>
+    <cDialog :dialog="dialog" @toClose="toClose">
+      <template v-slot:info>
+        <el-col :span="24" class="dialog_one" v-if="dialog.type == '1'">
+          <cForm :span="24" :fields="formFields" :form="form" :rules="rules" @save="toSave" label-width="auto">
+            <template #icon>
+              <cUpload
+                :model="`${'icon'}`"
+                :limit="1"
+                listType="picture-card"
+                url="/visit/api/files/follow/doctor/upload"
+                accept="*"
+                :list="form.icon"
+                @change="onUpload"
+              ></cUpload>
+            </template>
+          </cForm>
+        </el-col>
+      </template>
+    </cDialog>
+  </div>
+</template>
+
+<script setup lang="ts">
+// 基础
+import type { FormRules } from 'element-plus';
+import type { Ref } from 'vue';
+import { ref, onMounted, getCurrentInstance, reactive } from 'vue';
+import { ElMessage } from 'element-plus';
+// 接口
+import { NurseStore } from '@/stores/users/nurse';
+import type { IQueryResult } from '@/util/types.util';
+const nurseAxios = NurseStore();
+const { proxy } = getCurrentInstance() as any;
+// 加载中
+const loading: Ref<any> = ref(false);
+let list: Ref<any> = ref([]);
+let total: Ref<number> = ref(0);
+let skip = 0;
+let limit: number = proxy.$limit;
+let fields: Ref<any[]> = ref([
+  { label: '账号', model: 'account', isSearch: true },
+  { label: '姓名', model: 'name', isSearch: true },
+  { label: '手机号', model: 'mobile', isSearch: true },
+  { label: '医院名称', model: 'hos_name', isSearch: true },
+  { label: '科室名称', model: 'dept_name', isSearch: true },
+  { label: '职务', model: 'title', isSearch: true },
+  { label: '职称', model: 'post', isSearch: true }
+]);
+// 操作
+let opera: Ref<any[]> = ref([
+  { label: '修改', method: 'edit' },
+  { label: '删除', method: 'del', confirm: true, type: 'danger' }
+]);
+// 查询数据
+let searchForm: Ref<any> = ref({});
+// 弹框
+const dialog: Ref<any> = ref({ title: '信息管理', show: false, type: '1' });
+const form: Ref<any> = ref({ file: [] });
+const formFields: Ref<any> = ref([
+  { label: '账号', model: 'account' },
+  { label: '密码', model: 'password', type: 'password' },
+  { label: '姓名', model: 'name' },
+  { label: '头像', model: 'icon', custom: true },
+  { label: '手机号', model: 'mobile' },
+  { label: '医院名称', model: 'hos_name' },
+  { label: '科室名称', model: 'dept_name' },
+  { label: '职务', model: 'title' },
+  { label: '职称', model: 'post' },
+  { label: '简介', model: 'content', type: 'textarea' }
+]);
+const rules = reactive<FormRules>({
+  account: [{ required: true, message: '请输入账号', trigger: 'blur' }],
+  password: [{ required: true, message: '请输入密码', trigger: 'blur' }],
+  name: [{ required: true, message: '请输入姓名', trigger: 'blur' }],
+  mobile: [{ required: true, message: '请输入手机号', trigger: 'blur' }],
+  hos_name: [{ required: true, message: '请输入医院名称', trigger: 'blur' }],
+  dept_name: [{ required: true, message: '请输入科室名称', trigger: 'blur' }],
+  title: [{ required: true, message: '请输入职务', trigger: 'blur' }],
+  post: [{ required: true, message: '请输入职称', trigger: 'blur' }]
+});
+// 请求
+onMounted(async () => {
+  loading.value = true;
+  await search({ skip, limit });
+  loading.value = false;
+});
+const search = async (e: { skip: number; limit: number }) => {
+  const info = { skip: e.skip, limit: e.limit, ...searchForm.value };
+  const res: IQueryResult = await nurseAxios.query(info);
+  if (res.errcode == '0') {
+    list.value = res.data;
+    total.value = res.total;
+  }
+};
+const toSearch = (query: any) => {
+  searchForm.value = query;
+  search({ skip, limit });
+};
+const onUpload = (e: { model: string; value: Array<[]> }) => {
+  const { model, value } = e;
+  form.value[model] = value;
+};
+// 提交保存
+const toSave = async (data: any) => {
+  let res: IQueryResult;
+  if (data._id) res = await nurseAxios.update(data);
+  else res = await nurseAxios.create(data);
+  if (res.errcode == 0) {
+    ElMessage({ type: `success`, message: `维护信息成功` });
+    toClose();
+  }
+};
+// 新增
+const toAdd = () => {
+  dialog.value = { title: '信息管理', show: true, type: '1' };
+};
+// 修改
+const toEdit = async (data: any) => {
+  let res: IQueryResult = await nurseAxios.fetch(data._id);
+  if (res.errcode == '0') {
+    form.value = res.data;
+    dialog.value = { title: '信息管理', show: true, type: '1' };
+  }
+};
+// 删除
+const toDel = async (data: any) => {
+  let res: IQueryResult = await nurseAxios.del(data._id);
+  if (res.errcode == 0) {
+    ElMessage({ type: `success`, message: `刪除信息成功` });
+    search({ skip, limit });
+  }
+};
+// 关闭弹框
+const toClose = () => {
+  form.value = { file: [] };
+  dialog.value = { show: false };
+  search({ skip, limit });
+};
+</script>
+<style scoped lang="scss">
+.main {
+  .two {
+    margin: 0 0 10px 0;
+  }
+}
+</style>

+ 165 - 0
src/views/nurse/index.vue

@@ -0,0 +1,165 @@
+<template>
+  <div id="index">
+    <el-row>
+      <el-col :span="24" class="main animate__animated animate__backInRight" v-loading="loading">
+        <el-col :span="24" class="one">
+          <cSearch :is_title="false" :is_search="true" :fields="fields" @search="toSearch"> </cSearch>
+        </el-col>
+        <el-col :span="24" class="two">
+          <cButton @toAdd="toAdd()"> </cButton>
+        </el-col>
+        <el-col :span="24" class="thr">
+          <cTable :fields="fields" :opera="opera" :list="list" @query="search" :total="total" @edit="toEdit" @del="toDel"></cTable>
+        </el-col>
+      </el-col>
+    </el-row>
+    <cDialog :dialog="dialog" @toClose="toClose">
+      <template v-slot:info>
+        <el-col :span="24" class="dialog_one" v-if="dialog.type == '1'">
+          <cForm :span="24" :fields="formFields" :form="form" :rules="rules" @save="toSave" label-width="auto">
+            <template #icon>
+              <cUpload
+                :model="`${'icon'}`"
+                :limit="1"
+                listType="picture-card"
+                url="/visit/api/files/follow/nurse/upload"
+                accept="*"
+                :list="form.icon"
+                @change="onUpload"
+              ></cUpload>
+            </template>
+          </cForm>
+        </el-col>
+      </template>
+    </cDialog>
+  </div>
+</template>
+
+<script setup lang="ts">
+// 基础
+import type { FormRules } from 'element-plus';
+import type { Ref } from 'vue';
+import { ref, onMounted, getCurrentInstance, reactive } from 'vue';
+import { ElMessage } from 'element-plus';
+import { useRoute } from 'vue-router';
+// 接口
+import { NurseStore } from '@/stores/users/nurse';
+import type { IQueryResult } from '@/util/types.util';
+const nurseAxios = NurseStore();
+const { proxy } = getCurrentInstance() as any;
+// 路由
+const route = useRoute();
+// 加载中
+const loading: Ref<any> = ref(false);
+let id: Ref<any> = ref(route.query.id);
+let list: Ref<any> = ref([]);
+let total: Ref<number> = ref(0);
+let skip = 0;
+let limit: number = proxy.$limit;
+let fields: Ref<any[]> = ref([
+  { label: '账号', model: 'account', isSearch: true },
+  { label: '姓名', model: 'name', isSearch: true },
+  { label: '手机号', model: 'mobile', isSearch: true },
+  { label: '医院名称', model: 'hos_name', isSearch: true },
+  { label: '科室名称', model: 'dept_name', isSearch: true },
+  { label: '职务', model: 'title', isSearch: true },
+  { label: '职称', model: 'post', isSearch: true }
+]);
+// 操作
+let opera: Ref<any[]> = ref([
+  { label: '修改', method: 'edit' },
+  { label: '删除', method: 'del', confirm: true, type: 'danger' }
+]);
+// 查询数据
+let searchForm: Ref<any> = ref({});
+// 弹框
+const dialog: Ref<any> = ref({ title: '信息管理', show: false, type: '1' });
+const form: Ref<any> = ref({ icon: [], doctor: id.value });
+const formFields: Ref<any> = ref([
+  { label: '账号', model: 'account' },
+  { label: '密码', model: 'password', type: 'password' },
+  { label: '姓名', model: 'name' },
+  { label: '头像', model: 'icon', custom: true },
+  { label: '手机号', model: 'mobile' },
+  { label: '医院名称', model: 'hos_name' },
+  { label: '科室名称', model: 'dept_name' },
+  { label: '职务', model: 'title' },
+  { label: '职称', model: 'post' },
+  { label: '简介', model: 'content', type: 'textarea' }
+]);
+const rules = reactive<FormRules>({
+  account: [{ required: true, message: '请输入账号', trigger: 'blur' }],
+  password: [{ required: true, message: '请输入密码', trigger: 'blur' }],
+  name: [{ required: true, message: '请输入姓名', trigger: 'blur' }],
+  mobile: [{ required: true, message: '请输入手机号', trigger: 'blur' }],
+  hos_name: [{ required: true, message: '请输入医院名称', trigger: 'blur' }],
+  dept_name: [{ required: true, message: '请输入科室名称', trigger: 'blur' }],
+  title: [{ required: true, message: '请输入职务', trigger: 'blur' }],
+  post: [{ required: true, message: '请输入职称', trigger: 'blur' }]
+});
+// 请求
+onMounted(async () => {
+  loading.value = true;
+  await search({ skip, limit });
+  loading.value = false;
+});
+const search = async (e: { skip: number; limit: number }) => {
+  const info = { skip: e.skip, limit: e.limit, ...searchForm.value, doctor: id.value };
+  const res: IQueryResult = await nurseAxios.query(info);
+  if (res.errcode == '0') {
+    list.value = res.data;
+    total.value = res.total;
+  }
+};
+const toSearch = (query: any) => {
+  searchForm.value = query;
+  search({ skip, limit });
+};
+const onUpload = (e: { model: string; value: Array<[]> }) => {
+  const { model, value } = e;
+  form.value[model] = value;
+};
+// 提交保存
+const toSave = async (data: any) => {
+  let res: IQueryResult;
+  if (data._id) res = await nurseAxios.update(data);
+  else res = await nurseAxios.create(data);
+  if (res.errcode == 0) {
+    ElMessage({ type: `success`, message: `维护信息成功` });
+    toClose();
+  }
+};
+// 新增
+const toAdd = () => {
+  dialog.value = { title: '信息管理', show: true, type: '1' };
+};
+// 修改
+const toEdit = async (data: any) => {
+  let res: IQueryResult = await nurseAxios.fetch(data._id);
+  if (res.errcode == '0') {
+    form.value = res.data;
+    dialog.value = { title: '信息管理', show: true, type: '1' };
+  }
+};
+// 删除
+const toDel = async (data: any) => {
+  let res: IQueryResult = await nurseAxios.del(data._id);
+  if (res.errcode == 0) {
+    ElMessage({ type: `success`, message: `刪除信息成功` });
+    search({ skip, limit });
+  }
+};
+// 关闭弹框
+const toClose = () => {
+  form.value = { icon: [], doctor: id.value };
+  dialog.value = { show: false };
+  search({ skip, limit });
+};
+</script>
+<style scoped lang="scss">
+.main {
+  .two {
+    margin: 0 0 10px 0;
+  }
+}
+</style>

+ 170 - 0
src/views/patient/index.vue

@@ -0,0 +1,170 @@
+<template>
+  <div id="index">
+    <el-row>
+      <el-col :span="24" class="main animate__animated animate__backInRight" v-loading="loading">
+        <el-col :span="24" class="one">
+          <cSearch :is_title="false" :is_search="true" :fields="fields" @search="toSearch"> </cSearch>
+        </el-col>
+        <el-col :span="24" class="two">
+          <cButton @toAdd="toAdd()"> </cButton>
+        </el-col>
+        <el-col :span="24" class="thr">
+          <cTable :fields="fields" :opera="opera" :list="list" @query="search" :total="total" @edit="toEdit" @del="toDel"></cTable>
+        </el-col>
+      </el-col>
+    </el-row>
+    <cDialog :dialog="dialog" @toClose="toClose">
+      <template v-slot:info>
+        <el-col :span="24" class="dialog_one" v-if="dialog.type == '1'">
+          <cForm :span="24" :fields="formFields" :form="form" :rules="rules" @save="toSave" label-width="auto">
+            <template #icon>
+              <cUpload
+                :model="`${'icon'}`"
+                :limit="1"
+                listType="picture-card"
+                url="/visit/api/files/follow/patient/upload"
+                accept="*"
+                :list="form.icon"
+                @change="onUpload"
+              ></cUpload>
+            </template>
+            <template #gender>
+              <el-option v-for="i in genderList" :key="i.value" :label="i.label" :value="i.value"></el-option>
+            </template>
+          </cForm>
+        </el-col>
+      </template>
+    </cDialog>
+  </div>
+</template>
+
+<script setup lang="ts">
+// 基础
+import type { FormRules } from 'element-plus';
+import type { Ref } from 'vue';
+import { ref, onMounted, getCurrentInstance, reactive } from 'vue';
+import { ElMessage } from 'element-plus';
+// 接口
+import { PatientStore } from '@/stores/users/patient';
+import type { IQueryResult } from '@/util/types.util';
+const patientAxios = PatientStore();
+const { proxy } = getCurrentInstance() as any;
+// 加载中
+const loading: Ref<any> = ref(false);
+let list: Ref<any> = ref([]);
+let total: Ref<number> = ref(0);
+let skip = 0;
+let limit: number = proxy.$limit;
+let fields: Ref<any[]> = ref([
+  { label: '姓名', model: 'name', isSearch: true },
+  { label: '就诊编号/卡号', model: 'card_no', isSearch: true },
+  { label: '手机号', model: 'mobile', isSearch: true },
+  { label: '性别', model: 'gender', isSearch: true },
+  { label: '年龄', model: 'age', isSearch: true },
+  { label: '住址', model: 'address', isSearch: true },
+  { label: '紧急联系人', model: 'urgent_name', isSearch: true },
+  { label: '紧急联系人手机', model: 'urgent_mobile', isSearch: true }
+]);
+// 操作
+let opera: Ref<any[]> = ref([
+  { label: '修改', method: 'edit' },
+  { label: '删除', method: 'del', confirm: true, type: 'danger' }
+]);
+// 查询数据
+let searchForm: Ref<any> = ref({});
+// 弹框
+const dialog: Ref<any> = ref({ title: '信息管理', show: false, type: '1' });
+const form: Ref<any> = ref({ file: [] });
+const formFields: Ref<any> = ref([
+  { label: '姓名', model: 'name' },
+  { label: '就诊编号/卡号', model: 'card_no' },
+  { label: '手机号', model: 'mobile' },
+  { label: '性别', model: 'gender', type: 'select' },
+  { label: '年龄', model: 'age' },
+  { label: '住址', model: 'address' },
+  { label: '紧急联系人', model: 'urgent_name' },
+  { label: '紧急联系人手机', model: 'urgent_mobile' },
+  { label: '病例', model: 'emrs' },
+  { label: '简介', model: 'content', type: 'textarea' }
+]);
+const rules = reactive<FormRules>({
+  name: [{ required: true, message: '请输入姓名', trigger: 'blur' }],
+  card_no: [{ required: true, message: '请输入就诊编号/卡号', trigger: 'blur' }],
+  mobile: [{ required: true, message: '请输入手机号', trigger: 'blur' }],
+  gender: [{ required: true, message: '请输入性别', trigger: 'blur' }],
+  age: [{ required: true, message: '请输入年龄', trigger: 'blur' }],
+  address: [{ required: true, message: '请输入住址', trigger: 'blur' }],
+  urgent_name: [{ required: true, message: '请输入紧急联系人', trigger: 'blur' }],
+  urgent_mobile: [{ required: true, message: '请输入紧急联系人手机', trigger: 'blur' }]
+});
+// 字典表
+const genderList: Ref<any> = ref([
+  { label: '男', value: '男' },
+  { label: '女', value: '女' }
+]);
+// 请求
+onMounted(async () => {
+  loading.value = true;
+  await search({ skip, limit });
+  loading.value = false;
+});
+const search = async (e: { skip: number; limit: number }) => {
+  const info = { skip: e.skip, limit: e.limit, ...searchForm.value };
+  const res: IQueryResult = await patientAxios.query(info);
+  if (res.errcode == '0') {
+    list.value = res.data;
+    total.value = res.total;
+  }
+};
+const toSearch = (query: any) => {
+  searchForm.value = query;
+  search({ skip, limit });
+};
+const onUpload = (e: { model: string; value: Array<[]> }) => {
+  const { model, value } = e;
+  form.value[model] = value;
+};
+// 提交保存
+const toSave = async (data: any) => {
+  let res: IQueryResult;
+  if (data._id) res = await patientAxios.update(data);
+  else res = await patientAxios.create(data);
+  if (res.errcode == 0) {
+    ElMessage({ type: `success`, message: `维护信息成功` });
+    toClose();
+  }
+};
+// 新增
+const toAdd = () => {
+  dialog.value = { title: '信息管理', show: true, type: '1' };
+};
+// 修改
+const toEdit = async (data: any) => {
+  let res: IQueryResult = await patientAxios.fetch(data._id);
+  if (res.errcode == '0') {
+    form.value = res.data;
+    dialog.value = { title: '信息管理', show: true, type: '1' };
+  }
+};
+// 删除
+const toDel = async (data: any) => {
+  let res: IQueryResult = await patientAxios.del(data._id);
+  if (res.errcode == 0) {
+    ElMessage({ type: `success`, message: `刪除信息成功` });
+    search({ skip, limit });
+  }
+};
+// 关闭弹框
+const toClose = () => {
+  form.value = { file: [] };
+  dialog.value = { show: false };
+  search({ skip, limit });
+};
+</script>
+<style scoped lang="scss">
+.main {
+  .two {
+    margin: 0 0 10px 0;
+  }
+}
+</style>

+ 111 - 0
src/views/system/config/index.vue

@@ -0,0 +1,111 @@
+<template>
+  <div id="index">
+    <el-row>
+      <el-col :span="24" class="main animate__animated animate__backInRight" v-loading="loading">
+        <el-col :span="24" class="one">
+          <cSearch :is_title="false"></cSearch>
+        </el-col>
+        <el-col :span="24" class="two">
+          <cForm :span="24" :fields="fields" :form="form" :rules="rules" @save="toSave" label-width="auto">
+            <template #logo_url="{ item }">
+              <cUpload
+                :model="item.model"
+                :limit="1"
+                url="/visit/api/files/follow/config/upload"
+                :list="form[item.model]"
+                listType="picture-card"
+                @change="onUpload"
+              ></cUpload>
+            </template>
+            <template #group_url="{ item }">
+              <cUpload
+                :model="item.model"
+                :limit="1"
+                url="/visit/api/files/follow/config/upload"
+                :list="form[item.model]"
+                listType="picture-card"
+                @change="onUpload"
+              ></cUpload>
+            </template>
+            <template #friend_url="{ item }">
+              <cUpload
+                :model="item.model"
+                :limit="1"
+                url="/visit/api/files/follow/config/upload"
+                :list="form[item.model]"
+                listType="picture-card"
+                @change="onUpload"
+              ></cUpload>
+            </template>
+            <template #user_url="{ item }">
+              <cUpload
+                :model="item.model"
+                :limit="1"
+                url="/visit/api/files/follow/config/upload"
+                :list="form[item.model]"
+                listType="picture-card"
+                @change="onUpload"
+              ></cUpload>
+            </template>
+            <template #agreement>
+              <cEditor v-model="form.agreement" url="/visit/api/files/follow/config/upload"></cEditor>
+            </template>
+          </cForm>
+        </el-col>
+      </el-col>
+    </el-row>
+  </div>
+</template>
+
+<script setup lang="ts">
+// 基础
+import type { Ref } from 'vue';
+import { ref, reactive, onMounted } from 'vue';
+import { ElMessage } from 'element-plus';
+import type { FormRules } from 'element-plus';
+// 接口
+import { ConfigStore } from '@/stores/basic/config';
+import type { IQueryResult } from '@/util/types.util';
+const configAxios = ConfigStore();
+
+// 加载中
+const loading: Ref<any> = ref(false);
+
+// 表单
+let form: Ref<any> = ref({});
+let fields: Ref<any[]> = ref([
+  { label: 'logo', model: 'logo_url', custom: true },
+  { label: '群组logo', model: 'group_url', custom: true },
+  { label: '好友logo', model: 'friend_url', custom: true },
+  { label: '用户默认头像', model: 'user_url', custom: true },
+  { label: '用户协议和隐私协议', model: 'agreement', custom: true },
+  { label: '底部文案', model: 'bottom_title' }
+]);
+const rules = reactive<FormRules>({});
+// 请求
+onMounted(async () => {
+  loading.value = true;
+  await search();
+  loading.value = false;
+});
+const search = async () => {
+  let res: IQueryResult = await configAxios.query();
+  if (res.errcode == '0') {
+    form.value = res.data;
+  }
+};
+const onUpload = (e: { model: string; value: Array<[]> }) => {
+  const { model, value } = e;
+  form.value[model] = value;
+};
+const toSave = async (data) => {
+  let res: IQueryResult;
+  if (data._id) res = await configAxios.update(data);
+  else res = await configAxios.create(data);
+  if (res.errcode == 0) {
+    ElMessage({ type: `success`, message: `维护信息成功` });
+    search();
+  }
+};
+</script>
+<style scoped lang="scss"></style>

+ 0 - 196
src/views/system/dict/index.vue

@@ -1,196 +0,0 @@
-<template>
-  <div id="index">
-    <el-row>
-      <el-col :span="24" class="main animate__animated animate__backInRight" v-loading="loading">
-        <el-col :span="24" class="one">
-          <cSearch :is_title="false" :is_search="true" :fields="fields" @search="toSearch"> </cSearch>
-        </el-col>
-        <el-col :span="24" class="two">
-          <cButton @toAdd="toAdd()"> </cButton>
-        </el-col>
-        <el-col :span="24" class="thr">
-          <cTable :fields="fields" :opera="opera" :list="list" @query="search" :total="total" @edit="toEdit" @del="toDel">
-            <template #type="{ item, row }">
-              <template v-if="item.model === 'type'">
-                <el-link size="small" type="primary" @click="toType(row)">{{ getProps(row, item.model) }}</el-link>
-              </template>
-            </template>
-            <template #is_use="{ row }">
-              <el-switch
-                v-model="row.is_use"
-                inline-prompt
-                active-text="是"
-                inactive-text="否"
-                active-value="0"
-                inactive-value="1"
-                @click="handleChange(row)"
-              ></el-switch>
-            </template>
-          </cTable>
-        </el-col>
-      </el-col>
-    </el-row>
-    <cDialog :dialog="dialog" @toClose="toClose">
-      <template v-slot:info>
-        <el-col :span="24" class="dialog_one" v-if="dialog.type == '1'">
-          <cForm :span="24" :fields="formFields" :form="form" :rules="rules" @save="onSubmit">
-            <template #is_use>
-              <el-radio v-for="(i, index) in is_useList" :key="index" :label="i.value">{{ i.label }}</el-radio>
-            </template>
-          </cForm>
-        </el-col>
-      </template>
-    </cDialog>
-  </div>
-</template>
-<script lang="ts" setup>
-// 基础
-import _ from 'lodash';
-import type { FormRules } from 'element-plus';
-import type { Ref } from 'vue';
-import { ref, onMounted, getCurrentInstance, reactive } from 'vue';
-import { ElMessage, ElMessageBox } from 'element-plus';
-import { useRouter } from 'vue-router';
-
-// 接口
-import { DictDataStore } from '@/stores/basic/dictData'; //
-import { DictTypeStore } from '@/stores/basic/dictType'; //
-import type { IQueryResult } from '@/util/types.util';
-const dictType = DictTypeStore();
-const dictData = DictDataStore();
-// 路由
-const router = useRouter();
-const { proxy } = getCurrentInstance() as any;
-// 加载中
-const loading = ref(false);
-// 列表数据
-let list: Ref<any> = ref([]);
-let total: Ref<number> = ref(0);
-let skip = 0;
-let limit: number = proxy.$limit;
-let fields: Ref<any[]> = ref([
-  { label: '字典名称', model: 'title', isSearch: true },
-  { label: '字典类型', model: 'type', custom: true },
-  { label: '是否启用', model: 'is_use', custom: true },
-  { label: '备注', model: 'remark' }
-]);
-// 操作
-let opera: Ref<any[]> = ref([
-  { label: '修改', method: 'edit' },
-  { label: '删除', method: 'del', confirm: true, type: 'danger' }
-]);
-// 弹框
-const dialog: Ref<{ type: string; show: boolean; title: string }> = ref({ type: '1', show: false, title: '信息管理' });
-let form: Ref<{}> = ref({});
-// 表单
-let formFields: Ref<any[]> = ref([
-  { label: '字典名称', model: 'title' },
-  { label: '字典类型', model: 'type' },
-  { label: '是否启用', model: 'is_use', type: 'radio' },
-  { label: '备注', model: 'remark', type: 'textarea' }
-]);
-const rules = reactive<FormRules>({
-  name: [{ required: true, message: '请输入字典名称', trigger: 'blur' }],
-  type: [{ required: true, message: '请选择字典类型', trigger: 'blur' }]
-});
-// 查询数据
-let searchForm: Ref<any> = ref({});
-// 字典表
-let is_useList: Ref<any> = ref([]);
-onMounted(async () => {
-  loading.value = true;
-  await searchOther();
-  await search({ skip, limit });
-  loading.value = false;
-});
-// 查询
-const search = async (e: { skip: number; limit: number }) => {
-  const { skip, limit } = e;
-  const condition = _.cloneDeep(searchForm.value);
-  let info = { limit: limit, skip: skip, ...condition };
-  let res: IQueryResult = await dictType.query(info);
-  if (res.errcode == 0) {
-    list.value = res.data;
-    total.value = res.total;
-  }
-};
-const toSearch = (query: any) => {
-  searchForm.value = query;
-  search({ skip, limit });
-};
-const getProps = (data: any, prop: any) => {
-  return _.get(data, prop);
-};
-// 新增
-const toAdd = () => {
-  dialog.value = { title: '信息管理', show: true, type: '1' };
-};
-// 修改
-const toEdit = async (data: any) => {
-  let res: IQueryResult = await dictType.fetch(data._id);
-  if (res.errcode == 0) {
-    form.value = res.data as {};
-    dialog.value = { title: '信息管理', show: true, type: '1' };
-  }
-};
-// 提交
-const onSubmit = async (data: any) => {
-  let res: IQueryResult;
-  if (data._id) res = await dictType.update(data);
-  else res = await dictType.create(data);
-  if (res.errcode == 0) {
-    ElMessage({ type: `success`, message: `维护信息成功` });
-    toClose();
-  }
-};
-// 删除
-const toDel = async (data: any) => {
-  let res: IQueryResult = await dictType.del(data._id);
-  if (res.errcode == 0) {
-    ElMessage({ type: `success`, message: `刪除信息成功` });
-    search({ skip, limit });
-  }
-};
-// 弹框关闭
-const toClose = () => {
-  form.value = {};
-  searchForm.value = {};
-  dialog.value = { title: '信息管理', show: false, type: '1' };
-  search({ skip, limit });
-};
-// 字典类型跳转
-const toType = (data: any) => {
-  router.push({ path: '/system/dictData', query: { id: data._id, type: data.type } });
-};
-// 查询其他信息
-const searchOther = async () => {
-  let res: IQueryResult = await dictData.query({ type: 'is_use', is_use: '0' });
-  if (res.errcode == 0) is_useList.value = res.data;
-};
-// 修改是否启用
-const handleChange = (row: any) => {
-  const text = row.is_use === '0' ? '启用' : '停用';
-  ElMessageBox.confirm('确认要"' + text + '""' + row.type + '"吗?', '提示', {
-    confirmButtonText: '确定',
-    cancelButtonText: '取消',
-    type: 'warning'
-  })
-    .then(async () => {
-      let res: IQueryResult;
-      if (row._id) res = await dictType.update(row);
-      if (res.errcode == 0) {
-        ElMessage({ type: `success`, message: `修改成功` });
-      }
-    })
-    .catch(() => {
-      row.is_use = row.is_use === '0' ? '1' : '0';
-    });
-};
-</script>
-<style lang="scss" scoped>
-.main {
-  .two {
-    margin: 0 0 10px 0;
-  }
-}
-</style>

+ 0 - 194
src/views/system/dictData/index.vue

@@ -1,194 +0,0 @@
-<template>
-  <div id="index">
-    <el-row>
-      <el-col :span="24" class="main animate__animated animate__backInRight" v-loading="loading">
-        <el-col :span="24" class="one">
-          <cSearch :is_title="false" :is_search="true" :fields="fields" @search="toSearch"> </cSearch>
-        </el-col>
-        <el-col :span="24" class="two">
-          <cButton @toAdd="toAdd()">
-            <template v-slot:custom>
-              <el-button type="primary" @click="toBack">返回</el-button>
-            </template>
-          </cButton>
-        </el-col>
-        <el-col :span="24" class="thr">
-          <cTable :fields="fields" :opera="opera" :list="list" @query="search" :total="total" @edit="toEdit" @del="toDel">
-            <template #is_use="{ row }">
-              <el-switch
-                v-model="row.is_use"
-                inline-prompt
-                active-text="是"
-                inactive-text="否"
-                active-value="0"
-                inactive-value="1"
-                @click="handleChange(row)"
-              ></el-switch>
-            </template>
-          </cTable>
-        </el-col>
-      </el-col>
-    </el-row>
-    <cDialog :dialog="dialog" @toClose="toClose">
-      <template v-slot:info>
-        <el-col :span="24" class="dialog_one" v-if="dialog.type == '1'">
-          <cForm :span="24" :fields="formFields" :form="form" :rules="rules" @save="toSave">
-            <template #is_use>
-              <el-radio v-for="i in is_useList" :key="i._id" :label="i.value">{{ i.label }}</el-radio>
-            </template>
-          </cForm>
-        </el-col>
-      </template>
-    </cDialog>
-  </div>
-</template>
-
-<script setup lang="ts">
-// 基础
-import _ from 'lodash';
-import type { FormRules } from 'element-plus';
-import type { Ref } from 'vue';
-import { ref, onMounted, getCurrentInstance, reactive } from 'vue';
-import { ElMessage, ElMessageBox } from 'element-plus';
-import { useRoute, useRouter } from 'vue-router';
-// 接口
-import { DictDataStore } from '@/stores/basic/dictData';
-import type { IQueryResult } from '@/util/types.util';
-const dictData = DictDataStore();
-// 路由
-const route = useRoute();
-const router = useRouter();
-const { proxy } = getCurrentInstance() as any;
-// 加载中
-const loading: Ref<any> = ref(false);
-// 列表数据
-let list: Ref<any> = ref([]);
-let total: Ref<number> = ref(0);
-let skip = 0;
-let limit: number = proxy.$limit;
-let fields: Ref<any[]> = ref([
-  { label: '类型', model: 'type' },
-  { label: '标签', model: 'label', isSearch: true },
-  { label: '键值', model: 'value', isSearch: true },
-  { label: '排序', model: 'sort', type: 'number' },
-  { label: '是否启用', model: 'is_use', custom: true }
-]);
-// 操作
-let opera: Ref<any[]> = ref([
-  { label: '修改', method: 'edit' },
-  { label: '删除', method: 'del', confirm: true, type: 'danger' }
-]);
-// 弹框
-const dialog: Ref<{ type: string; show: boolean; title: string }> = ref({ type: '1', show: false, title: '信息管理' });
-let form: Ref<{}> = ref({});
-// 表单
-let formFields: Ref<any[]> = ref([
-  { label: '类型', model: 'type', options: { disabled: true } },
-  { label: '标签', model: 'label' },
-  { label: '键值', model: 'value' },
-  { label: '排序', model: 'sort', type: 'number' },
-  { label: '是否启用', model: 'is_use', type: 'radio' }
-]);
-const rules = reactive<FormRules>({
-  label: [{ required: true, message: '请输入标签', trigger: 'blur' }],
-  value: [{ required: true, message: '请输入键值', trigger: 'blur' }]
-});
-// 查询数据
-let searchForm: Ref<any> = ref({});
-// 字典表
-let is_useList: Ref<any> = ref([]);
-// 请求
-onMounted(async () => {
-  loading.value = true;
-  await searchOther();
-  await search({ skip, limit });
-  loading.value = false;
-});
-const search = async (e: { skip: number; limit: number }) => {
-  const { skip, limit } = e;
-  const condition = _.cloneDeep(searchForm.value);
-  let type = route.query.type;
-  let info = { limit: limit, skip: skip, ...condition, type: type };
-  let res: IQueryResult = await dictData.query(info);
-  if (res.errcode == 0) {
-    list.value = res.data;
-    total.value = res.total;
-  }
-};
-const toSearch = (query: any) => {
-  searchForm.value = query;
-  search({ skip, limit });
-};
-// 新增
-const toAdd = () => {
-  let type = route.query.type;
-  form.value = { type: type };
-  dialog.value = { title: '信息管理', show: true, type: '1' };
-};
-// 修改
-const toEdit = async (data: any) => {
-  form.value = data;
-  dialog.value = { title: '信息管理', show: true, type: '1' };
-};
-// 提交保存
-const toSave = async (data: any) => {
-  let res: IQueryResult;
-  if (data._id) res = await dictData.update(data);
-  else res = await dictData.create(data);
-  if (res.errcode == 0) {
-    ElMessage({ type: `success`, message: `维护信息成功` });
-    toClose();
-  }
-};
-// 删除
-const toDel = async (data: any) => {
-  let res: IQueryResult = await dictData.del(data._id);
-  if (res.errcode == 0) {
-    ElMessage({ type: `success`, message: `刪除信息成功` });
-    search({ skip, limit });
-  }
-};
-// 弹框关闭
-const toClose = () => {
-  form.value = {};
-  dialog.value = { title: '信息管理', show: false, type: '1' };
-  search({ skip, limit });
-};
-// 查询其他信息
-const searchOther = async () => {
-  let res: IQueryResult;
-  // 是否启用
-  res = await dictData.query({ type: 'is_use', is_use: '0' });
-  if (res.errcode == '0') is_useList.value = res.data;
-};
-// 返回上一页
-const toBack = () => {
-  router.push({ path: '/system/dict' });
-};
-// 修改是否启用
-const handleChange = (row: any) => {
-  const text = row.is_use === '0' ? '启用' : '停用';
-  ElMessageBox.confirm('确认要"' + text + '""' + row.label + '"吗?', '提示', {
-    confirmButtonText: '确定',
-    cancelButtonText: '取消',
-    type: 'warning'
-  })
-    .then(async () => {
-      let res: IQueryResult;
-      if (row._id) res = await dictData.update(row);
-      if (res.errcode == 0) {
-        ElMessage({ type: `success`, message: `修改成功` });
-      }
-    })
-    .catch(() => {
-      row.is_use = row.is_use === '0' ? '1' : '0';
-    });
-};
-</script>
-<style scoped lang="scss">
-.main {
-  .two {
-    margin: 0 0 10px 0;
-  }
-}
-</style>

+ 29 - 14
src/views/system/menus/index.vue

@@ -108,19 +108,34 @@ import { ElMessage, ElMessageBox } from 'element-plus';
 
 // 接口
 import { MenusStore } from '@/stores/basic/menus'; // 菜单
-import { DictDataStore } from '@/stores/basic/dictData'; // 字典表
 import type { IQueryResult } from '@/util/types.util';
 const menusAxios = MenusStore();
-const dictAxios = DictDataStore();
 
 let list: Ref<any> = ref([]);
 // 表单
 let form: Ref<any> = ref({});
 const tab: Ref<any> = ref('basic');
 // 字典表
-const is_useList: Ref<any> = ref([]);
-const iconList: Ref<any> = ref([]);
-const typeList: Ref<any> = ref([]);
+const is_useList: Ref<any> = ref([
+  { label: '是', value: '0' },
+  { label: '否', value: '1' }
+]);
+const iconList: Ref<any> = ref([
+  { label: 'icon-yonghu', value: 'icon-yonghu' },
+  { label: 'icon-shezhi', value: 'icon-shezhi' },
+  { label: 'icon-yishengguanli', value: 'icon-yishengguanli' },
+  { label: 'icon-icon-person-hushi', value: 'icon-icon-person-hushi' },
+  { label: 'icon--_bingren', value: 'icon--_bingren' },
+  { label: 'icon-qunzu', value: 'icon-qunzu' },
+  { label: 'icon-tubiao_-', value: 'icon-tubiao_-' },
+  { label: 'icon-guanggaoguanli', value: 'icon-guanggaoguanli' },
+  { label: 'icon-yonghuxinxi', value: 'icon-yonghuxinxi' }
+]);
+const typeList: Ref<any> = ref([
+  { label: '目录', value: '0' },
+  { label: '菜单', value: '1' },
+  { label: '子页面', value: '2' }
+]);
 // 加载中
 const loading: Ref<any> = ref(false);
 // 弹框
@@ -212,15 +227,15 @@ const toClose = () => {
 // 查询其他信息
 const searchOther = async () => {
   let res: IQueryResult;
-  // 是否启用
-  res = await dictAxios.query({ type: 'is_use', is_use: '0' });
-  if (res.errcode == '0') is_useList.value = res.data;
-  // 图标
-  res = await dictAxios.query({ type: 'info_icon', is_use: '0' });
-  if (res.errcode == '0') iconList.value = res.data;
-  // 菜单类型
-  res = await dictAxios.query({ type: 'menus_type', is_use: '0' });
-  if (res.errcode == '0') typeList.value = res.data;
+  // // 是否启用
+  // res = await dictAxios.query({ type: 'is_use', is_use: '0' });
+  // if (res.errcode == '0') is_useList.value = res.data;
+  // // 图标
+  // res = await dictAxios.query({ type: 'info_icon', is_use: '0' });
+  // if (res.errcode == '0') iconList.value = res.data;
+  // // 菜单类型
+  // res = await dictAxios.query({ type: 'menus_type', is_use: '0' });
+  // if (res.errcode == '0') typeList.value = res.data;
 };
 // 修改是否启用
 const handleChange = (row: any) => {

+ 4 - 6
src/views/system/role/detail.vue

@@ -36,10 +36,8 @@ import type { FormRules } from 'element-plus';
 import { useRoute } from 'vue-router';
 // 接口
 import { RoleStore } from '@/stores/basic/role'; // 角色
-import { DictDataStore } from '@/stores/basic/dictData'; // 字典表
 import type { IQueryResult } from '@/util/types.util';
 const roleAxios = RoleStore();
-const dictAxios = DictDataStore();
 // 路由
 const route = useRoute();
 // 加载中
@@ -59,7 +57,10 @@ const rules = reactive<FormRules>({
   is_use: [{ required: true, message: '请选择是否启用', trigger: 'blur' }]
 });
 // 字典表
-const is_useList: Ref<any> = ref([]);
+const is_useList: Ref<any> = ref([
+  { label: '是', value: '0' },
+  { label: '否', value: '1' }
+]);
 const menuList: Ref<any> = ref([]);
 // 请求
 onMounted(async () => {
@@ -91,9 +92,6 @@ const toSave = async (data: any) => {
 // 查询其他信息
 const searchOther = async () => {
   let res: IQueryResult;
-  // 是否启用
-  res = await dictAxios.query({ type: 'is_use', is_use: '0' });
-  if (res.errcode == '0') is_useList.value = res.data;
   // 查询菜单
   res = await roleAxios.am();
   if (res.errcode == '0') menuList.value = res.data;

+ 0 - 12
src/views/system/role/index.vue

@@ -36,10 +36,8 @@ import { ElMessage, ElMessageBox } from 'element-plus';
 import { useRouter } from 'vue-router';
 // 接口
 import { RoleStore } from '@/stores/basic/role'; // 角色
-import { DictDataStore } from '@/stores/basic/dictData'; // 字典表
 import type { IQueryResult } from '@/util/types.util';
 const roleAxios = RoleStore();
-const dictAxios = DictDataStore();
 const { proxy } = getCurrentInstance() as any;
 // 路由
 const router = useRouter();
@@ -61,12 +59,9 @@ let opera: Ref<any[]> = ref([
 ]);
 // 查询数据
 let searchForm: Ref<any> = ref({});
-// 字典表
-const is_useList: Ref<any> = ref([]);
 // 请求
 onMounted(async () => {
   loading.value = true;
-  await searchOther();
   await search({ skip, limit });
   loading.value = false;
 });
@@ -98,13 +93,6 @@ const toDel = async (data: any) => {
     search({ skip, limit });
   }
 };
-// 查询其他信息
-const searchOther = async () => {
-  let res: IQueryResult;
-  // 是否启用
-  res = await dictAxios.query({ type: 'is_use', is_use: '0' });
-  if (res.errcode == '0') is_useList.value = res.data;
-};
 // 修改是否启用
 const handleChange = (row: any) => {
   const text = row.is_use === '0' ? '启用' : '停用';

+ 0 - 104
src/views/user/admin/detail.vue

@@ -1,104 +0,0 @@
-<template>
-  <div id="detail">
-    <el-row>
-      <el-col :span="24" class="main animate__animated animate__backInRight" v-loading="loading">
-        <el-col :span="24" class="one">
-          <cSearch :is_back="true" @toBack="toBack"></cSearch>
-        </el-col>
-        <el-col :span="24" class="two">
-          <cForm :span="24" :fields="fields" :form="form" :rules="rules" @save="toSave" label-width="auto">
-            <template #role>
-              <el-option v-for="i in roleList" :key="i._id" :label="i.name" :value="i._id"></el-option>
-            </template>
-            <template #region>
-              <el-option v-for="i in regionList" :key="i._id" :label="i.name" :value="i._id"></el-option>
-            </template>
-          </cForm>
-        </el-col>
-      </el-col>
-    </el-row>
-  </div>
-</template>
-
-<script setup lang="ts">
-// 基础
-import type { Ref } from 'vue';
-import { ref, reactive, onMounted } from 'vue';
-import { ElMessage } from 'element-plus';
-import type { FormRules } from 'element-plus';
-import { useRoute } from 'vue-router';
-// 接口
-import { AdminStore } from '@/stores/users/admin';
-import { RoleStore } from '@/stores/basic/role'; // 角色
-import { RegionStore } from '@/stores/basic/region'; // 区域
-import { DictDataStore } from '@/stores/basic/dictData'; // 字典表
-import type { IQueryResult } from '@/util/types.util';
-const adminAxios = AdminStore();
-const dictAxios = DictDataStore();
-const roleAxios = RoleStore();
-const regionAxios = RegionStore();
-// 路由
-const route = useRoute();
-// 加载中
-const loading: Ref<any> = ref(false);
-// 表单
-let form: Ref<any> = ref({});
-let fields: Ref<any[]> = ref([
-  { label: '账号', model: 'account', options: { disabled: true } },
-  { label: '姓名', model: 'name' },
-  { label: '手机号', model: 'phone' },
-  { label: '角色', model: 'role', type: 'select' },
-  { label: '区域', model: 'region', type: 'select' }
-]);
-const rules = reactive<FormRules>({
-  name: [{ required: true, message: '请输入姓名', trigger: 'blur' }],
-  phone: [{ required: true, message: '请输入手机号', trigger: 'blur' }],
-  role: [{ required: true, message: '请输入角色', trigger: 'blur' }]
-});
-// 字典表
-const roleList: Ref<any> = ref([]);
-const regionList: Ref<any> = ref([]);
-const statusList: Ref<any> = ref([]);
-// 请求
-onMounted(async () => {
-  loading.value = true;
-  await searchOther();
-  await search();
-  loading.value = false;
-});
-const search = async () => {
-  let id = route.query.id;
-  if (id) {
-    let res: IQueryResult = await adminAxios.fetch(id);
-    if (res.errcode == '0') form.value = res.data as {};
-  }
-};
-// 保存
-const toSave = async (data: any) => {
-  let res: IQueryResult;
-  if (data._id) res = await adminAxios.update(data);
-  else res = await adminAxios.create(data);
-  if (res.errcode == 0) {
-    ElMessage({ type: `success`, message: `维护信息成功` });
-    toBack();
-  }
-};
-// 查询其他信息
-const searchOther = async () => {
-  let res: IQueryResult;
-  // 角色
-  res = await roleAxios.query({ is_use: '0' });
-  if (res.errcode == '0') roleList.value = res.data;
-  // 状态
-  res = await dictAxios.query({ type: 'exam_status', is_use: '0' });
-  if (res.errcode == '0') statusList.value = res.data;
-  // 区域
-  res = await regionAxios.query({ is_use: '0' });
-  if (res.errcode == '0') regionList.value = res.data;
-};
-// 返回上一页
-const toBack = () => {
-  window.history.go(-1);
-};
-</script>
-<style scoped lang="scss"></style>

+ 0 - 161
src/views/user/admin/index.vue

@@ -1,161 +0,0 @@
-<template>
-  <div id="index">
-    <el-row>
-      <el-col :span="24" class="main animate__animated animate__backInRight" v-loading="loading">
-        <el-col :span="24" class="one">
-          <cSearch :is_title="false" :is_search="true" :fields="fields" @search="toSearch">
-            <template #status>
-              <el-option v-for="i in statusList" :key="i.value" :label="i.label" :value="i.value"></el-option>
-            </template>
-          </cSearch>
-        </el-col>
-        <el-col :span="24" class="two">
-          <cTable :fields="fields" :opera="opera" :list="list" @query="search" :total="total" @exam="toExam" @edit="toEdit" @del="toDel"> </cTable>
-        </el-col>
-      </el-col>
-    </el-row>
-    <cDialog :dialog="dialog" @toClose="toClose">
-      <template v-slot:info>
-        <el-col :span="24" class="dialog_one" v-if="dialog.type == '1'">
-          <cForm :span="24" :fields="formFields" :form="form" :rules="{}" @save="toSave" label-width="auto">
-            <template #status>
-              <el-option v-for="i in statusList" :key="i.value" :label="i.label" :value="i.value"></el-option>
-            </template>
-          </cForm>
-        </el-col>
-      </template>
-    </cDialog>
-  </div>
-</template>
-
-<script setup lang="ts">
-// 基础
-import type { Ref } from 'vue';
-import { onMounted, ref, getCurrentInstance } from 'vue';
-import { ElMessage } from 'element-plus';
-import { useRouter } from 'vue-router';
-// 接口
-import { AdminStore } from '@/stores/users/admin';
-import { RoleStore } from '@/stores/basic/role'; // 角色
-import { DictDataStore } from '@/stores/basic/dictData'; // 字典表
-import type { IQueryResult } from '@/util/types.util';
-const adminAxios = AdminStore();
-const dictAxios = DictDataStore();
-const roleAxios = RoleStore();
-const { proxy } = getCurrentInstance() as any;
-// 路由
-const router = useRouter();
-// 加载中
-const loading: Ref<any> = ref(false);
-let list: Ref<any> = ref([]);
-let total: Ref<number> = ref(0);
-let skip = 0;
-let limit: number = proxy.$limit;
-let fields: Ref<any[]> = ref([
-  { label: '账号', model: 'account', isSearch: true },
-  { label: '昵称', model: 'name', isSearch: true },
-  { label: '手机号', model: 'phone', isSearch: true },
-  { label: '角色', model: 'role', format: (i: any) => getDict(i, roleList.value, 'role') },
-  { label: '状态', model: 'status', format: (i: any) => getDict(i, statusList.value, 'status'), type: 'select', isSearch: true }
-]);
-// 操作
-let opera: Ref<any[]> = ref([
-  { label: '审核', method: 'exam', type: 'warning', display: (i: any) => i.status == '0' },
-  { label: '修改', method: 'edit' },
-  { label: '删除', method: 'del', confirm: true, type: 'danger' }
-]);
-// 查询数据
-let searchForm: Ref<any> = ref({});
-// 字典表
-const roleList: Ref<any> = ref([]);
-const statusList: Ref<any> = ref([]);
-// 弹框
-const dialog: Ref<any> = ref({ title: '审核管理', show: false, type: '1' });
-const form: Ref<any> = ref({ file: [] });
-const formFields: Ref<any> = ref([{ label: '状态', model: 'status', type: 'select' }]);
-// 请求
-onMounted(async () => {
-  loading.value = true;
-  await searchOther();
-  await search({ skip, limit });
-  loading.value = false;
-});
-const search = async (e: { skip: number; limit: number }) => {
-  const info = { skip: e.skip, limit: e.limit, ...searchForm.value };
-  const res: IQueryResult = await adminAxios.query(info);
-  if (res.errcode == '0') {
-    list.value = res.data;
-    total.value = res.total;
-  }
-};
-const toSearch = (query: any) => {
-  searchForm.value = query;
-  search({ skip, limit });
-};
-const getDict = (e: any, model: any, type: any) => {
-  if (type == 'role') {
-    let data: any = model.find((i: any) => i._id == e);
-    if (data) return data.name;
-    else return '暂无';
-  } else if (type == 'status') {
-    let data: any = model.find((i: any) => i.value == e);
-    if (data) return data.label;
-    else return '暂无';
-  }
-};
-// 审核
-const toExam = async (data: any) => {
-  let res: IQueryResult = await adminAxios.fetch(data._id);
-  if (res.errcode == '0') {
-    form.value = res.data;
-    dialog.value = { title: '审核管理', show: true, type: '1' };
-  }
-};
-// 提交保存
-const toSave = async (data: any) => {
-  let res: IQueryResult = await adminAxios.update(data);
-  if (res.errcode == '0') {
-    ElMessage({ message: '信息审核成功', type: 'success' });
-    toClose();
-  } else {
-    ElMessage({ message: `${res.errmsg}`, type: 'error' });
-  }
-};
-// 修改
-const toEdit = (data: any) => {
-  router.push({ path: '/admin/detail', query: { id: data._id } });
-};
-// 删除
-const toDel = async (data: any) => {
-  let res: IQueryResult = await adminAxios.del(data._id);
-  if (res.errcode == 0) {
-    ElMessage({ type: `success`, message: `刪除信息成功` });
-    search({ skip, limit });
-  }
-};
-
-// 关闭弹框
-const toClose = () => {
-  form.value = {};
-  dialog.value = { show: false };
-  search({ skip, limit });
-};
-
-// 查询其他信息
-const searchOther = async () => {
-  let res: IQueryResult;
-  // 角色
-  res = await roleAxios.query({ is_use: '0' });
-  if (res.errcode == '0') roleList.value = res.data;
-  // 状态
-  res = await dictAxios.query({ type: 'exam_status', is_use: '0' });
-  if (res.errcode == '0') statusList.value = res.data;
-};
-</script>
-<style scoped lang="scss">
-.main {
-  .two {
-    margin: 0 0 10px 0;
-  }
-}
-</style>

+ 0 - 258
src/views/user/user/chat.vue

@@ -1,258 +0,0 @@
-<template>
-  <div id="detail">
-    <el-row>
-      <el-col :span="24" class="main animate__animated animate__backInRight" v-loading="loading">
-        <el-col :span="24" class="one">
-          <cSearch :is_back="true" @toBack="toBack"></cSearch>
-        </el-col>
-        <el-col :span="14" class="two">
-          <div style="overflow: auto" v-scrollBottom>
-            <ul v-infinite-scroll="load" class="infinite-list">
-              <el-col :span="24" class="list" v-for="item in list" :key="item._id">
-                <el-col :span="24" class="two_1" v-if="item.speaker == user._id">
-                  <el-col class="time" v-if="item.time != ''">{{ item.time }}</el-col>
-                  <el-col :span="24" class="content">
-                    <el-col :span="2" class="logo">
-                      <el-image
-                        v-if="user && user.logo.length != 0"
-                        :src="user.logo[0].url || '../../assets/bglogin.jpg'"
-                        style="width: 60px; height: 60px; border-radius: 60px"
-                        mode="widthFix"
-                      ></el-image>
-                    </el-col>
-                    <el-col :span="8" v-if="item.msg_type == '0'">
-                      <text class="text">{{ item.content }}</text>
-                    </el-col>
-                    <el-col :span="8" class="image" v-else>
-                      <el-image :src="item.content" style="width: 15vw" mode="widthFix"></el-image>
-                    </el-col>
-                  </el-col>
-                </el-col>
-                <el-col :span="24" class="two_2" v-else>
-                  <el-col class="time" v-if="item.time != ''">{{ item.time }}</el-col>
-                  <el-col :span="24" class="content">
-                    <el-col :span="8" v-if="item.msg_type == '0'">
-                      <text class="text">{{ item.content }}</text>
-                    </el-col>
-                    <el-col :span="8" class="image" v-else>
-                      <el-image :src="item.content" style="width: 15vw" mode="widthFix"></el-image>
-                    </el-col>
-                    <el-col :span="2" class="logo">
-                      <el-image
-                        v-if="config && config.file.length != 0"
-                        :src="config.file[0].url"
-                        style="width: 60px; height: 60px; border-radius: 60px"
-                        mode="widthFix"
-                      ></el-image>
-                    </el-col>
-                  </el-col>
-                </el-col>
-              </el-col>
-            </ul>
-          </div>
-        </el-col>
-        <el-col :span="14" class="bottom">
-          <el-col :span="20" class="input">
-            <el-input v-model="input" type="textarea" placeholder="请输入" />
-          </el-col>
-          <el-col :span="4" class="button">
-            <el-button type="primary" @click="toSend">发送</el-button>
-            <cUpload class="upload" :limit="1" accept="*" url="/files/travel/chat/upload" :list="file" @change="onUpload"> </cUpload>
-          </el-col>
-        </el-col>
-      </el-col>
-    </el-row>
-  </div>
-</template>
-<script setup lang="ts">
-// 基础
-import moment from 'moment';
-import type { Ref } from 'vue';
-import { onMounted, ref, getCurrentInstance } from 'vue';
-import { useRoute } from 'vue-router';
-import store from '@/stores/counter';
-import { ElMessage } from 'element-plus';
-// 接口
-import { ChatStore } from '@/stores/users/chat';
-import { ConfigStore } from '@/stores/basic/config';
-import { UserStore } from '@/stores/users/user';
-import type { IQueryResult } from '@/util/types.util';
-const { proxy } = getCurrentInstance() as any;
-
-const chatAxios = ChatStore();
-const configAxios = ConfigStore();
-const userAxios = UserStore();
-let admin: Ref<any> = ref(store.state.user);
-// 路由
-const route = useRoute();
-// 加载中
-const loading: Ref<any> = ref(false);
-let list: Ref<any> = ref([]);
-let total: Ref<number> = ref(0);
-let skip = 0;
-let page = 0;
-let limit: number = proxy.$limit;
-const user: Ref<any> = ref({ logo: [] });
-const config: Ref<any> = ref({ file: [] });
-const file: Ref<any> = ref([]);
-const input: Ref<any> = ref('');
-// 字典表
-// 请求
-onMounted(async () => {
-  loading.value = true;
-  await searchOther();
-  await search({ skip, limit });
-  loading.value = false;
-});
-const search = async (e: { skip: number; limit: number }) => {
-  if (user.value._id) {
-    const info = { skip: e.skip, limit: e.limit, user: user.value._id };
-    const res: any = await chatAxios.query(info);
-    if (res.errcode == '0') {
-      list.value = res.data.reverse();
-      total.value = res.total;
-    }
-  }
-};
-// 查询其他信息
-const searchOther = async () => {
-  let id = route.query.id;
-  let res: IQueryResult;
-  if (id) {
-    res = await userAxios.fetch(id);
-    if (res.errcode == '0') user.value = res.data;
-    // 全部已读
-    await chatAxios.read({ user: id });
-  }
-  res = await configAxios.query();
-  if (res.errcode == '0') {
-    config.value = res.data;
-  }
-};
-// 发送
-const toSend = async () => {
-  let res: IQueryResult;
-  let form: any = { user: user.value._id, speaker: admin.value._id, content: input.value, msg_type: '0', time: moment().format('YYYY-MM-DD HH:mm:ss') };
-  // 发送给服务器消息
-  res = await chatAxios.create(form);
-  if (res.errcode == 0) {
-    ElMessage({ type: `success`, message: `发送消息信息成功` });
-    input.value = '';
-    search({ skip, limit });
-  }
-};
-// 上传
-const onUpload = async (e: { value: Array<any> }) => {
-  const { value } = e;
-  let res: IQueryResult;
-  let form: any = { user: user.value._id, speaker: admin.value._id, content: value[0].url, msg_type: '1', time: moment().format('YYYY-MM-DD HH:mm:ss') };
-  // 发送给服务器消息
-  res = await chatAxios.create(form);
-  if (res.errcode == 0) {
-    ElMessage({ type: `success`, message: `发送消息信息成功` });
-    file.value = [];
-    search({ skip, limit });
-  }
-};
-// 下拉查看聊天记录
-const load = () => {
-  if (total.value != 0) {
-    if (total.value > limit) {
-      page = page + 1;
-      limit = limit * page;
-      search({ skip, limit });
-    } else ElMessage({ type: `warning`, message: `已经到底了!` });
-  }
-};
-// 返回上一页
-const toBack = () => {
-  window.history.go(-1);
-};
-</script>
-<style scoped lang="scss">
-.main {
-  .two {
-    padding: 20px;
-    border: 1px solid #d5d5da;
-    background: #f1f1f1;
-    border-radius: 5px;
-
-    .infinite-list {
-      height: 550px;
-      padding: 0;
-      margin: 0;
-      list-style: none;
-    }
-
-    .list {
-      display: flex;
-      flex-direction: column;
-
-      .two_1 {
-        .time {
-          text-align: center;
-          color: #858585;
-          font-size: 12px;
-        }
-
-        .content {
-          display: flex;
-          align-items: center;
-
-          .logo {
-            height: 60px;
-          }
-
-          .text {
-            padding: 12px;
-            background: #ffffff;
-            border-radius: 0px 12px 12px 12px;
-          }
-        }
-      }
-
-      .two_2 {
-        text-align: right;
-
-        .time {
-          text-align: center;
-          color: #858585;
-          font-size: 12px;
-        }
-
-        .content {
-          display: flex;
-          align-items: center;
-          justify-content: right;
-
-          .logo {
-            height: 60px;
-          }
-
-          .text {
-            padding: 12px;
-            border-radius: 12px 0px 12px 12px;
-            background: #16f80f;
-          }
-        }
-      }
-    }
-  }
-
-  .bottom {
-    display: flex;
-    align-items: center;
-    padding: 5px 0 0 0;
-
-    .button {
-      display: flex;
-      margin: 10px 0 0 5px;
-
-      .upload {
-        text-align: right;
-        padding: 0 0 0 5px;
-      }
-    }
-  }
-}
-</style>

+ 0 - 187
src/views/user/user/index.vue

@@ -1,187 +0,0 @@
-<template>
-  <div id="index">
-    <el-row>
-      <el-col :span="24" class="main animate__animated animate__backInRight" v-loading="loading">
-        <el-col :span="24" class="one">
-          <cSearch :is_title="false" :is_search="true" :fields="fields" @search="toSearch"> 
-            <template #type>
-              <el-option v-for="i in typeList" :key="i.value" :label="i.label" :value="i.value"></el-option>
-            </template>
-          </cSearch>
-        </el-col>
-        <el-col :span="24" class="two">
-          <cTable :fields="fields" :opera="opera" :list="list" @query="search" :total="total" @chat="toChat" @edit="toEdit" @del="toDel">
-            <template #is_read="{ item, row }">
-              <template v-if="item.model === 'is_read'">
-                <span :class="[row.is_read == '未读' ? 'text' : '']">{{ row.is_read }}</span>
-              </template>
-            </template>
-          </cTable>
-        </el-col>
-      </el-col>
-    </el-row>
-    <cDialog :dialog="dialog" @toClose="toClose">
-      <template v-slot:info>
-        <el-col :span="24" class="dialog_one" v-if="dialog.type == '1'">
-          <cForm :span="24" :fields="formFields" :form="form" :rules="{}" @save="toSave" label-width="auto">
-            <template #gender>
-              <el-option v-for="i in genderList" :key="i.value" :label="i.label" :value="i.value"></el-option>
-            </template>
-            <template #type>
-              <el-option v-for="i in typeList" :key="i.value" :label="i.label" :value="i.value"></el-option>
-            </template>
-            <template #status>
-              <el-option v-for="i in statusList" :key="i.value" :label="i.label" :value="i.value"></el-option>
-            </template>
-          </cForm>
-        </el-col>
-      </template>
-    </cDialog>
-  </div>
-</template>
-
-<script setup lang="ts">
-// 基础
-import type { Ref } from 'vue';
-import { onMounted, ref, getCurrentInstance } from 'vue';
-import { ElMessage } from 'element-plus';
-import { useRouter } from 'vue-router';
-// 接口
-import { UserStore } from '@/stores/users/user';
-import { DictDataStore } from '@/stores/basic/dictData'; // 字典表
-import type { IQueryResult } from '@/util/types.util';
-const userAxios = UserStore();
-const dictAxios = DictDataStore();
-const { proxy } = getCurrentInstance() as any;
-// 路由
-const router = useRouter();
-// 加载中
-const loading: Ref<any> = ref(false);
-let list: Ref<any> = ref([]);
-let total: Ref<number> = ref(0);
-let skip = 0;
-let limit: number = proxy.$limit;
-let fields: Ref<any[]> = ref([
-  { label: '微信用户标识', model: 'openid' },
-  { label: '真实姓名', model: 'name', isSearch: true },
-  { label: '昵称', model: 'nick_name', isSearch: true },
-  { label: '性别', model: 'gender', format: (i: any) => getDict(i, genderList.value) },
-  { label: '手机号', model: 'phone', isSearch: true },
-  { label: '生日', model: 'birthday' },
-  { label: '类型', model: 'type', format: (i: any) => getDict(i, typeList.value), isSearch: true },
-  { label: '所在城市', model: 'city', isSearch: true },
-  { label: '是否已读', model: 'is_read', custom: true }
-]);
-// 操作
-let opera: Ref<any[]> = ref([
-  { label: '修改', method: 'edit' },
-  { label: '删除', method: 'del', confirm: true, type: 'danger' },
-  { label: '聊天记录', method: 'chat' }
-]);
-// 查询数据
-let searchForm: Ref<any> = ref({});
-// 字典表
-const genderList: Ref<any> = ref([]);
-const statusList: Ref<any> = ref([]);
-const typeList: Ref<any> = ref([]);
-// 弹框
-const dialog: Ref<any> = ref({ title: '信息管理', show: false, type: '1' });
-const form: Ref<any> = ref({ file: [] });
-const formFields: Ref<any> = ref([
-  { label: '微信用户标识', model: 'openid', options: { disabled: true } },
-  { label: '真实姓名', model: 'name' },
-  { label: '昵称', model: 'nick_name' },
-  { label: '性别', model: 'gender', type: 'select' },
-  { label: '手机号', model: 'phone' },
-  { label: '生日', model: 'birthday', type: 'date' },
-  { label: '类型', model: 'type', type: 'select' },
-  { label: '所在城市', model: 'city' },
-  { label: '状态', model: 'status', type: 'select' }
-]);
-// 请求
-onMounted(async () => {
-  loading.value = true;
-  await searchOther();
-  await search({ skip, limit });
-  loading.value = false;
-});
-const search = async (e: { skip: number; limit: number }) => {
-  const info = { skip: e.skip, limit: e.limit, ...searchForm.value };
-  const res: IQueryResult = await userAxios.user(info);
-  if (res.errcode == '0') {
-    list.value = res.data;
-    total.value = res.total;
-  }
-};
-const toSearch = (query: any) => {
-  searchForm.value = query;
-  search({ skip, limit });
-};
-const getDict = (e: any, model: any) => {
-  let data: any = model.find((i: any) => i.value == e);
-  if (data) return data.label;
-  else return '暂无';
-};
-// 提交保存
-const toSave = async (data: any) => {
-  delete data.is_read;
-  let res: IQueryResult = await userAxios.update(data);
-  if (res.errcode == '0') {
-    ElMessage({ message: '信息审核成功', type: 'success' });
-    toClose();
-  } else {
-    ElMessage({ message: `${res.errmsg}`, type: 'error' });
-  }
-};
-// 修改
-const toEdit = async (data: any) => {
-  let res: IQueryResult = await userAxios.fetch(data._id);
-  if (res.errcode == '0') {
-    form.value = res.data;
-    dialog.value = { title: '信息管理', show: true, type: '1' };
-  }
-};
-// 聊天记录
-const toChat = async (data: any) => {
-  router.push({ path: '/user/chat', query: { id: data._id } });
-};
-// 删除
-const toDel = async (data: any) => {
-  let res: IQueryResult = await userAxios.del(data._id);
-  if (res.errcode == 0) {
-    ElMessage({ type: `success`, message: `刪除信息成功` });
-    search({ skip, limit });
-  }
-};
-
-// 关闭弹框
-const toClose = () => {
-  form.value = {};
-  dialog.value = { show: false };
-  search({ skip, limit });
-};
-
-// 查询其他信息
-const searchOther = async () => {
-  let res: IQueryResult;
-  // 性别
-  res = await dictAxios.query({ type: 'gender', is_use: '0' });
-  if (res.errcode == '0') genderList.value = res.data;
-  // 类型
-  res = await dictAxios.query({ type: 'user_type', is_use: '0' });
-  if (res.errcode == '0') typeList.value = res.data;
-  // 状态
-  res = await dictAxios.query({ type: 'exam_status', is_use: '0' });
-  if (res.errcode == '0') statusList.value = res.data;
-};
-</script>
-<style scoped lang="scss">
-.main {
-  .two {
-    margin: 0 0 10px 0;
-    .text {
-      color: #f10000;
-    }
-  }
-}
-</style>