浏览代码

Merge branch 'kingbase' of http://git.cc-lotus.info/Information/technique_admin into kingbase

zs 11 月之前
父节点
当前提交
2634dce59c

+ 1 - 1
README.md

@@ -1,6 +1,6 @@
 # web-template-vue3-js
 
-## 1.菜单设置
+## 1.目录设置
 ### 1.1 功能列表
 > 前端:主要是控制角色是否可以显示按钮
 > 服务:主要是用同一编码对接口的使用进行控制

+ 1 - 0
src/components/custom/custom-upload.vue

@@ -64,6 +64,7 @@ const outLimit = () => {
 };
 // 上传成功,response:成功信息,file:图片信息,fileList:图片列表
 const onSuccess = (response, file) => {
+  console.log(response)
   if (response.errcode !== 0) {
     ElMessage({ type: 'error', message: '删除成功' })
     return

+ 6 - 6
src/lang/package/en/pages.js

@@ -1,14 +1,14 @@
 export default {
   menus: {
-    dialogTitle: '菜单信息',
+    dialogTitle: '目录信息',
     is_default: '是否默认',
-    name: '菜单名称',
-    namePh: '请填写菜单名称',
+    name: '目录名称',
+    namePh: '请填写目录名称',
     route_name: '路由名称',
     route_namePh: '请填写路由名称',
     i18n_code: '国际化编码',
     i18n_codePh: '请填写国际化编码并确保与国际化文件中的编码一致',
-    parentName: '父级菜单',
+    parentName: '父级目录',
     icon: '图标',
     iconPh: '请选择图标',
     order_num: '顺序',
@@ -16,8 +16,8 @@ export default {
     pathPh: '请填写路由地址',
     component: '组件地址',
     componentPh: '请填写组件地址',
-    type: '菜单类型',
-    typePh: '请选择菜单类型',
+    type: '目录类型',
+    typePh: '请选择目录类型',
     is_use: '状态',
     remark: '备注',
     remarkPh: '请输入备注',

+ 2 - 1
src/lang/package/zh-cn/errorMessage.js

@@ -16,5 +16,6 @@ export default {
   FILE_FAULT: '文件错误',
   USER_NOT_BIND: '用户未绑定',
   BUSINESS: '业务错误',
-  REQUEST_ERROR: '接口请求发生错误'
+  REQUEST_ERROR: '接口请求发生错误',
+  USER_PERMISSION_ERROR: '用户权限异常,请重新登陆或联系管理员!'
 }

+ 1 - 1
src/lang/package/zh-cn/menus.js

@@ -4,7 +4,7 @@ export default {
   user: '用户管理',
   center: '个人中心',
   password: '修改密码',
-  system_menus: '菜单设置',
+  system_menus: '目录设置',
   system_role: '角色设置',
   system_parameter: '系统参数',
   system_dict: '字典管理',

+ 10 - 10
src/lang/package/zh-cn/pages.js

@@ -1,14 +1,14 @@
 export default {
   menus: {
-    dialogTitle: '菜单信息',
+    dialogTitle: '目录信息',
     is_default: '是否默认',
-    name: '菜单名称',
-    namePh: '请填写菜单名称',
+    name: '目录名称',
+    namePh: '请填写目录名称',
     route_name: '路由名称',
     route_namePh: '请填写路由名称',
     i18n_code: '国际化编码',
     i18n_codePh: '请填写国际化编码并确保与国际化文件中的编码一致',
-    parentName: '父级菜单',
+    parentName: '父级目录',
     icon: '图标',
     iconPh: '请选择图标',
     order_num: '顺序',
@@ -16,8 +16,8 @@ export default {
     pathPh: '请填写路由地址',
     component: '组件地址',
     componentPh: '请填写组件地址',
-    type: '菜单类型',
-    typePh: '请选择菜单类型',
+    type: '目录类型',
+    typePh: '请选择目录类型',
     is_use: '状态',
     remark: '备注',
     remarkPh: '请输入备注',
@@ -88,13 +88,13 @@ export default {
     valueMessage: '请输入数据选择值'
   },
   tags: {
-    addDialogTitle: '新增导航菜单',
-    upDialogTitle: '修改导航菜单',
+    addDialogTitle: '新增导航目录',
+    upDialogTitle: '修改导航目录',
     title: '标题',
     English: '英文标题',
     href: '路由',
-    children: '子菜单',
-    type: '是否有子菜单',
+    children: '子目录',
+    type: '是否有子目录',
     is_use: '是否启用',
     remark: '备注',
     sort: '排序',

+ 1 - 1
src/layout/parts/Sidebar.vue

@@ -39,7 +39,7 @@ watch(
   (newVal) => {
     if (newVal && newVal.id) {
       if (newVal && newVal.id) getMenu()
-      else ElMessage({ message: `暂无用户信息,无法获取菜单信息`, type: 'error' })
+      else ElMessage({ message: `暂无用户信息,无法获取目录信息`, type: 'error' })
     }
   },
   {

+ 5 - 5
src/layout/parts/Tagsbar.vue

@@ -14,7 +14,7 @@
         <SvgIcon class="close-icon" icon-class="close" v-if="!isAffix(tag)" @click.prevent.stop="closeSelectedTag(tag)"></SvgIcon>
       </router-link>
     </el-scrollbar>
-    <!-- tag标签操作菜单 -->
+    <!-- tag标签操作目录 -->
     <ul v-show="contentMenuVisible" class="contextmenu" :style="{ left: left + 'px', top: top + 'px' }">
       <li @click="refreshSelectedTag(selectedTag)">
         <SvgIcon icon-class="refresh"></SvgIcon>
@@ -87,7 +87,7 @@ watch(
   }
 )
 
-const contentMenuVisible = ref(false) // 右键菜单是否显示
+const contentMenuVisible = ref(false) // 右键目录是否显示
 watch(contentMenuVisible, (value) => {
   if (value) {
     document.body.addEventListener('click', closeContentMenu)
@@ -249,7 +249,7 @@ function closeAllTags(view) {
 }
 
 /**
- * 打开右键菜单
+ * 打开右键目录
  */
 function openContentMenu(tag, e) {
   const menuMinWidth = 105
@@ -264,7 +264,7 @@ function openContentMenu(tag, e) {
     left.value = l
   }
 
-  // 混合模式下,需要减去顶部菜单(fixed)的高度
+  // 混合模式下,需要减去顶部目录(fixed)的高度
   if (layout.value === 'mix') {
     top.value = e.clientY - 50
   } else {
@@ -276,7 +276,7 @@ function openContentMenu(tag, e) {
 }
 
 /**
- * 关闭右键菜单
+ * 关闭右键目录
  */
 function closeContentMenu() {
   contentMenuVisible.value = false

+ 1 - 1
src/layout/site.js

@@ -5,7 +5,7 @@ export const siteInfo = {
   zhTitle: '新一代信息技术孵化平台',
   logo_url: `${import.meta.env.VITE_BASE_URL}/src/assets/logo-jilinbai.png`
 }
-// 菜单设置
+// 目录设置
 export const menuInfo = {
   info: {
     display: false,

+ 1 - 1
src/router/guard.js

@@ -32,7 +32,7 @@ export const registerBeforeRouter = async (router) => {
       const userMenus = toRaw(userStore.menus)
       if (!userMenus || userMenus.length <= 0) {
         console.log('has token but no menus')
-        // 没有菜单,说明路由没有注册,需要注册路由,记录当前去哪里再跳转至路由
+        // 没有目录,说明路由没有注册,需要注册路由,记录当前去哪里再跳转至路由
         next({ path: '/route/loading', query: { redirectPath: getRedirectUri(to) } })
         return
       } else {

+ 5 - 5
src/router/register.js

@@ -1,7 +1,7 @@
 import { UserStore } from '@/store/user'
 import { cloneDeep, isArray, omit } from 'lodash-es'
 
-// 获取用户信息,返回菜单
+// 获取用户信息,返回目录
 export const getUserMeta = async (token) => {
   const userStore = UserStore()
   const result = await userStore.tokenView(token)
@@ -41,9 +41,9 @@ const toOneDimensional = (routes) => {
 // 添加路由
 export const addUserRoutes = (menus, router) => {
   return new Promise((resolve, reject) => {
-    // 将用户菜单转换成普通对象
+    // 将用户目录转换成普通对象
     const menuArr = toRaw(menus)
-    // 将用户菜单平铺成一维数组,并将目录过滤出去.目录不需要注册,不是组件
+    // 将用户目录平铺成一维数组,并将目录过滤出去.目录不需要注册,不是组件
     const menuOneDimensional = toOneDimensional(menuArr)
     // 将默认注册的路由平铺成一维数组
     const routesOneDimensional = toOneDimensional(router.getRoutes())
@@ -55,7 +55,7 @@ export const addUserRoutes = (menus, router) => {
 
 /**
  * 注册路由
- * @param {Array} menus 一维数组菜单
+ * @param {Array} menus 一维数组目录
  * @param {Array} defaultRoutes 默认路由一维数组
  * @param {*} router 路由实例
  */
@@ -80,7 +80,7 @@ const routesRegister = (menus, defaultRoutes, router) => {
       }
       router.addRoute(__def, route)
     } else if (type === '1' || type === '2') {
-      // 菜单 或 子菜单
+      // 目录 或 子目录
       const route = {
         path: path,
         name: route_name,

+ 12 - 1
src/views/home/index.vue

@@ -2,13 +2,18 @@
   <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>
+        <admin v-if="hasView('admin')"></admin>
       </el-col>
     </el-row>
   </div>
 </template>
 
 <script setup>
+import admin from './parts/admin.vue'
+import { UserStore } from '@/store/user'
+import { upperFirst, isArray } from 'lodash-es'
+const userStore = UserStore()
+const user = userStore.user
 // 加载中
 const loading = ref(false)
 // 请求
@@ -16,5 +21,11 @@ onMounted(async () => {
   loading.value = true
   loading.value = false
 })
+const hasView = (roleCode) => {
+  const rc = upperFirst(roleCode)
+  const ru = toRaw(user)
+  console.log(ru)
+  if (isArray(ru.role) && ru.role.includes(rc)) return true
+}
 </script>
 <style scoped lang="scss"></style>

+ 181 - 0
src/views/home/parts/admin.vue

@@ -0,0 +1,181 @@
+<template>
+  <el-row :gutter="20" style="height: 37vh">
+    <el-col :span="8" style="height: 100%">
+      <el-col :span="24"> {{ $t('符合您需求的成果') }} </el-col>
+      <el-col :span="24">
+        <custom-table :data="achieveData" :fields="achieveFields" :total="achieveTotal" height="30vh">
+          <template #rate="{ row }">
+            <el-rate v-model="row.rate" size="large" />
+          </template>
+        </custom-table>
+      </el-col>
+    </el-col>
+    <el-col :span="8" style="text-align: center">
+      <el-col :span="24" style="margin: 5vh 0; font-size: 18px; font-weight: 700"> {{ $t('当前时间') }} </el-col>
+      <el-col :span="24" style="font-weight: 500; font-size: 30px; padding-top: 5vh">
+        {{ nowTime }}
+      </el-col>
+    </el-col>
+    <el-col :span="8" style="text-align: center">
+      <div style="margin: 16vh 0">
+        <el-statistic title="在线用户数" :value="12934" />
+      </div>
+    </el-col>
+  </el-row>
+  <el-row :gutter="20" style="height: 37vh; margin-top: 5vh">
+    <el-col :span="8">
+      <el-col :span="24"> {{ $t('符合您成果的需求') }} </el-col>
+      <el-col :span="24">
+        <custom-table :data="reqData" :fields="reqFields" :total="reqTotal" height="30vh">
+          <template #rate="{ row }">
+            <el-rate v-model="row.rate" size="large" />
+          </template>
+        </custom-table>
+      </el-col>
+    </el-col>
+    <el-col :span="8">
+      <div ref="c1" style="width: 100%; height: 100%"></div>
+    </el-col>
+    <el-col :span="8">
+      <div ref="c2" style="width: 100%; height: 100%"></div>
+    </el-col>
+  </el-row>
+</template>
+
+<script setup>
+import * as echarts from 'echarts'
+import moment from 'moment'
+const achieveData = ref([{ name: '多种酶的催化剂', rate: 4 }])
+const achieveFields = [
+  { label: '需求标题', model: 'name' },
+  { label: '推荐指数', model: 'rate', custom: true }
+]
+const achieveTotal = ref(1)
+const reqData = ref([{ name: '蛋白质分子合成技术', rate: 5 }])
+const reqTotal = ref(1)
+
+const reqFields = [
+  { label: '供给成果', model: 'name' },
+  { label: '推荐指数', model: 'rate', custom: true }
+]
+const nowTime = ref()
+const setNowTime = () => {
+  setInterval(() => {
+    nowTime.value = moment().format('YYYY-MM-DD HH:mm:ss')
+  }, 1000)
+}
+setNowTime()
+
+const c1 = ref()
+const initC1 = () => {
+  const ch = echarts.init(c1.value)
+  const data1 = 1
+  const options = {
+    title: {
+      text: '成果统计',
+      left: 'center',
+      textStyle: {
+        fontSize: 28,
+        fontWeight: 600,
+        fontStyle: 'normal'
+      }
+    },
+    legend: {
+      orient: 'vertical',
+      left: 'left'
+    },
+    tooltip: {
+      trigger: 'item',
+      formatter: '{a} <br/>{b}: {c} ({d}%)'
+    },
+    series: [
+      {
+        name: '专利',
+        type: 'pie',
+        center: ['50%', '65%'],
+        radius: ['45%', '60%'],
+        startAngle: 360,
+        avoidLabelOverlap: true,
+        labelLine: {
+          normal: {
+            show: true
+          }
+        },
+        data: [
+          {
+            value: data1,
+            name: '蛋白质方向专利'
+          }
+        ]
+      }
+    ]
+  }
+  ch.setOption(options)
+  window.addEventListener('resize', function () {
+    ch.resize()
+  })
+}
+
+const c2 = ref()
+const initC2 = () => {
+  const dayList = [
+    `${moment().subtract(7, 'd').format('M-D')}`,
+    `${moment().subtract(6, 'd').format('M-D')}`,
+    `${moment().subtract(5, 'd').format('M-D')}`,
+    `${moment().subtract(4, 'd').format('M-D')}`,
+    `${moment().subtract(3, 'd').format('M-D')}`,
+    `${moment().subtract(2, 'd').format('M-D')}`,
+    `${moment().subtract(1, 'd').format('M-D')}`
+  ]
+  const ch = echarts.init(c2.value)
+  const options = {
+    title: {
+      text: '近七日业务统计'
+    },
+    tooltip: {
+      trigger: 'axis'
+    },
+    legend: {
+      data: ['供需发布数', '赛事进行数', '成果洽谈数']
+    },
+    xAxis: {
+      type: 'category',
+      boundaryGap: false,
+      data: dayList
+    },
+    yAxis: {
+      type: 'value'
+    },
+    series: [
+      {
+        name: '供需发布数',
+        type: 'line',
+        stack: 'Total',
+        data: [120, 132, 101, 134, 90, 230, 210]
+      },
+      {
+        name: '赛事进行数',
+        type: 'line',
+        stack: 'Total',
+        data: [220, 182, 191, 234, 290, 330, 310]
+      },
+      {
+        name: '成果洽谈数',
+        type: 'line',
+        stack: 'Total',
+        data: [150, 232, 201, 154, 190, 330, 410]
+      }
+    ]
+  }
+  ch.setOption(options)
+  window.addEventListener('resize', function () {
+    ch.resize()
+  })
+}
+
+onMounted(() => {
+  initC1()
+  initC2()
+})
+</script>
+<style scoped></style>

+ 4 - 3
src/views/platform/policy/index.vue

@@ -4,8 +4,8 @@
     <custom-button-bar :fields="buttonFields" @add="toAdd"></custom-button-bar>
     <custom-table :data="data" :fields="fields" @query="search" :total="total" :opera="opera" @exam="toExam" @edit="toEdit" @delete="toDelete">
       <template #is_use="{ row }">
-        <el-tag v-if="row.is_use == '0'" type="success" @click="toUse(row, '1')">启用</el-tag>
-        <el-tag v-else type="info" @click="toUse(row, '0')">禁用</el-tag>
+        <el-tag v-if="row.is_use == '0'" type="success" @click="toUse(row, '1')">{{ $t('common.is_use_abled') }}</el-tag>
+        <el-tag v-else type="info" @click="toUse(row, '0')">{{ $t('common.is_use_disabled') }}</el-tag>
       </template>
     </custom-table>
     <el-dialog v-model="dialog.show" :title="dialog.title" :destroy-on-close="false" @close="toClose">
@@ -144,13 +144,14 @@ const getDict = (data, model) => {
 // 添加
 const toAdd = () => {
   formFields.value = cloneDeep(formFieldsForCreate)
-  form.value = { type: '0' }
+  form.value = { type: '0', logo: [] }
   dialog.value = { type: '1', show: true, title: t('pages.news.addDialogTitle') }
 }
 // 修改
 const toEdit = (data) => {
   formFields.value = cloneDeep(formFieldsForUpdate)
   form.value = data
+  if (!form.value.logo) form.value.logo = []
   dialog.value = { type: '1', show: true, title: t('pages.news.upDialogTitle') }
 }
 // 删除

+ 17 - 1
src/views/route-loading/index.vue

@@ -8,6 +8,8 @@ import { UserStore } from '@/store/user'
 import { onMounted } from 'vue'
 import { useRouter, useRoute } from 'vue-router'
 import { get } from 'lodash-es'
+import i18n from '@/lang'
+import { ElMessageBox } from 'element-plus'
 const fullscreenLoading = ref(true)
 const router = useRouter()
 const route = useRoute()
@@ -15,13 +17,27 @@ const userStore = UserStore()
 // 进了这个页面了.那就是重来注册一遍路由了
 const token = localStorage.getItem('token')
 onMounted(async () => {
-  // 1.获取用户菜单
+  // 1.获取用户目录
   const reqResult = await getUserMeta(token)
   if (reqResult.errcode !== 0) {
     // 处理异常
     return
   }
   const menus = get(reqResult, 'menus')
+  if (menus.length <= 0) {
+    const nowRouteFullPath = router.currentRoute.value.fullPath
+    ElMessageBox.confirm(i18n.global.t('error.USER_PERMISSION_ERROR'), i18n.global.t('common.user_confirm'), {
+      confirmButtonText: i18n.global.t('common.re_login'),
+      cancelButtonText: i18n.global.t('common.reload'),
+      type: 'error'
+    })
+      .then(() => {
+        if (nowRouteFullPath !== '/login') window.location.href = `${import.meta.env.VITE_BASE_URL}/login`
+      })
+      .catch(() => {
+        if (nowRouteFullPath !== '/login') location.reload()
+      })
+  }
   // 注册路由
   await addUserRoutes(menus, router)
   userStore.setMenus(menus)

+ 5 - 5
src/views/system/dept/parts/resource.vue

@@ -35,12 +35,12 @@ onMounted(() => {
   if (!selectedKeys.includes('home')) roleTree.value.setChecked('home', true)
 })
 /**
- * 处理菜单:将目录,菜单,子页面,权限统一转成 {name,code}形式,code为唯一值
- * 目录,菜单,子页面:
+ * 处理目录:将目录,目录,子页面,权限统一转成 {name,code}形式,code为唯一值
+ * 目录,目录,子页面:
  *  route_name是唯一的,所以使用route_name作为code
  * 权限:
  *  code并不是唯一,但是加上route_name就是唯一的
- * @param {Array} list 菜单列表
+ * @param {Array} list 目录列表
  * @param {Array} route_names 将上级的route_name放入此数组中,在转为权限数据时,拼接成code
  */
 const dealMenu = (list, route_names = []) => {
@@ -53,7 +53,7 @@ const dealMenu = (list, route_names = []) => {
     const nextList = []
     // 先处理该页面配置
     if (config.length >= 0) {
-      // 如果有配置: 菜单,子页面两种情况,都统一处理
+      // 如果有配置: 目录,子页面两种情况,都统一处理
       for (const c of config) {
         const codeRouteNameArr = [...thisRouteNameArr]
         codeRouteNameArr.push(c.code)
@@ -61,7 +61,7 @@ const dealMenu = (list, route_names = []) => {
         nextList.push(cobj)
       }
     }
-    // 再处理菜单/子页面
+    // 再处理目录/子页面
     if (children.length > 0) {
       const nextRouteNames = [...thisRouteNameArr]
       const midResult = dealMenu(children, nextRouteNames)

+ 1 - 1
src/views/system/menus/index.vue

@@ -30,7 +30,7 @@ const list = ref([])
 const form = ref({})
 const typeList = [
   { label: '目录', value: '0' },
-  { label: '菜单', value: '1' },
+  { label: '目录', value: '1' },
   { label: '子页面', value: '2' }
 ]
 const iconList = ref([])

+ 1 - 1
src/views/system/menus/parts/parts/func.vue

@@ -14,7 +14,7 @@
             <el-col :span="24">ps:</el-col>
             <el-col :span="24"> 1.多个按钮可以对应同一个方法: e.g.:修改数据 和 单修改数据的状态 可以是多个按钮,但是使用一个接口处理</el-col>
             <el-col :span="24"> 2.按钮可以没有对应的接口: e.g.: 展示数据且不需要重新查询时,就不需要连接口 </el-col>
-            <el-col :span="24"> 3.按钮对应的接口可以交叉,例如菜单的添加下一级功能,这个功能其实是和创建使用一个接口,如果权限中给了创建接口权限,那在接口编码这里,写不写都无所谓,因为会叠加</el-col>
+            <el-col :span="24"> 3.按钮对应的接口可以交叉,例如目录的添加下一级功能,这个功能其实是和创建使用一个接口,如果权限中给了创建接口权限,那在接口编码这里,写不写都无所谓,因为会叠加</el-col>
           </el-row>
         </el-collapse-item>
       </el-collapse>

+ 1 - 1
src/views/system/menus/parts/parts/info.vue

@@ -1,6 +1,6 @@
 <template>
   <el-form label-position="left" label-width="100px">
-    <!-- 开发模式下显示该字段.即非开发模式下.所有的菜单都是非默认的 -->
+    <!-- 开发模式下显示该字段.即非开发模式下.所有的目录都是非默认的 -->
     <el-form-item v-if="is_dev" :label="$t('pages.menus.is_default')">
       <el-radio-group v-model="form.is_default">
         <el-radio label="0">{{ $t('common.yes') }}</el-radio>

+ 5 - 5
src/views/system/role/parts/form.vue

@@ -63,12 +63,12 @@ onMounted(() => {
   if (!selected.includes('home')) roleTree.value.setChecked('home', true)
 })
 /**
- * 处理菜单:将目录,菜单,子页面,权限统一转成 {name,code}形式,code为唯一值
- * 目录,菜单,子页面:
+ * 处理目录:将目录,目录,子页面,权限统一转成 {name,code}形式,code为唯一值
+ * 目录,目录,子页面:
  *  route_name是唯一的,所以使用route_name作为code
  * 权限:
  *  code并不是唯一,但是加上route_name就是唯一的
- * @param {Array} list 菜单列表
+ * @param {Array} list 目录列表
  * @param {Array} route_names 将上级的route_name放入此数组中,在转为权限数据时,拼接成code
  */
 const dealMenu = (list, route_names = []) => {
@@ -81,7 +81,7 @@ const dealMenu = (list, route_names = []) => {
     const nextList = []
     // 先处理该页面配置
     if (config.length >= 0) {
-      // 如果有配置: 菜单,子页面两种情况,都统一处理
+      // 如果有配置: 目录,子页面两种情况,都统一处理
       for (const c of config) {
         const codeRouteNameArr = [...thisRouteNameArr]
         codeRouteNameArr.push(c.code)
@@ -89,7 +89,7 @@ const dealMenu = (list, route_names = []) => {
         nextList.push(cobj)
       }
     }
-    // 再处理菜单/子页面
+    // 再处理目录/子页面
     if (children.length > 0) {
       const nextRouteNames = [...thisRouteNameArr]
       const midResult = dealMenu(children, nextRouteNames)

+ 2 - 2
src/views/system/tags/index.vue

@@ -153,11 +153,11 @@ const toDelete = async (data) => {
     search({ skip: 0, limit })
   }
 }
-// 添加子菜单
+// 添加子目录
 const toCadd = async () => {
   form.value.children.push({ type: '1', id: moment().valueOf() })
 }
-// 删除子菜单
+// 删除子目录
 const toCdel = async (item) => {
   const children = form.value.children.filter((i) => i.id != item.id)
   form.value.children = children