Prechádzať zdrojové kódy

Merge branch 'master' of http://git.cc-lotus.info/Information/cxyy-web

lrf 8 mesiacov pred
rodič
commit
f3d20dd2ce

BIN
public/images/center_1.png


+ 6 - 2
src/App.vue

@@ -1,7 +1,11 @@
-<script setup></script>
+<script setup>
+import zhCN from 'ant-design-vue/es/locale/zh_CN'
+</script>
 
 <template>
-  <router-view />
+  <a-config-provider :locale="zhCN">
+    <router-view />
+  </a-config-provider>
 </template>
 
 <style lang="scss">

+ 0 - 95
src/assets/icon/iconfont.css

@@ -1,95 +0,0 @@
-@font-face {
-  font-family: 'iconfont'; /* Project id 4079354 */
-  src:
-    url('iconfont.woff2?t=1685509924120') format('woff2'),
-    url('iconfont.woff?t=1685509924120') format('woff'),
-    url('iconfont.ttf?t=1685509924120') format('truetype');
-}
-
-.iconfont {
-  font-family: 'iconfont' !important;
-  font-size: 16px;
-  font-style: normal;
-  -webkit-font-smoothing: antialiased;
-  -moz-osx-font-smoothing: grayscale;
-}
-
-.icon-dengji:before {
-  content: '\e610';
-}
-
-.icon-shenhezhong:before {
-  content: '\e682';
-}
-
-.icon-dkw_shenheweitongguo:before {
-  content: '\e604';
-}
-
-.icon-shenhetongguo:before {
-  content: '\e668';
-}
-
-.icon-hearts-fill:before {
-  content: '\e702';
-}
-
-.icon-xiaoyouhui:before {
-  content: '\e601';
-}
-
-.icon-youjiantou-copy:before {
-  content: '\e654';
-}
-
-.icon-6ruxueshijian:before {
-  content: '\e88a';
-}
-
-.icon-zhuanyezhuanyeke:before {
-  content: '\e6a1';
-}
-
-.icon-commpany:before {
-  content: '\e612';
-}
-
-.icon-zhiwuguanli:before {
-  content: '\e60f';
-}
-
-.icon-guanzhu:before {
-  content: '\e611';
-}
-
-.icon-guanzhu1:before {
-  content: '\e600';
-}
-
-.icon-edu-line:before {
-  content: '\e63a';
-}
-
-.icon-gender:before {
-  content: '\e63e';
-}
-
-.icon-xingming:before {
-  content: '\e640';
-}
-
-.icon-jibenxinxi:before {
-  content: '\e67c';
-}
-
-.icon-iocn_be_concern:before {
-  content: '\e607';
-}
-
-.icon-tupianshangchuan:before {
-  content: '\e639';
-}
-
-.icon-wodeguanzhu:before {
-  content: '\e8bc';
-}

Rozdielové dáta súboru neboli zobrazené, pretože súbor je príliš veľký
+ 0 - 1
src/assets/icon/iconfont.js


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

@@ -1,149 +0,0 @@
-{
-  "id": "4079354",
-  "name": "校友信息登记",
-  "font_family": "iconfont",
-  "css_prefix_text": "icon-",
-  "description": "",
-  "glyphs": [
-    {
-      "icon_id": "1327399",
-      "name": "登记",
-      "font_class": "dengji",
-      "unicode": "e610",
-      "unicode_decimal": 58896
-    },
-    {
-      "icon_id": "1480896",
-      "name": "审核中",
-      "font_class": "shenhezhong",
-      "unicode": "e682",
-      "unicode_decimal": 59010
-    },
-    {
-      "icon_id": "2078809",
-      "name": "dkw_审核未通过",
-      "font_class": "dkw_shenheweitongguo",
-      "unicode": "e604",
-      "unicode_decimal": 58884
-    },
-    {
-      "icon_id": "10087856",
-      "name": "审核通过",
-      "font_class": "shenhetongguo",
-      "unicode": "e668",
-      "unicode_decimal": 58984
-    },
-    {
-      "icon_id": "35094512",
-      "name": "关心",
-      "font_class": "hearts-fill",
-      "unicode": "e702",
-      "unicode_decimal": 59138
-    },
-    {
-      "icon_id": "2726796",
-      "name": "校友会",
-      "font_class": "xiaoyouhui",
-      "unicode": "e601",
-      "unicode_decimal": 58881
-    },
-    {
-      "icon_id": "10515596",
-      "name": "右箭头",
-      "font_class": "youjiantou-copy",
-      "unicode": "e654",
-      "unicode_decimal": 58964
-    },
-    {
-      "icon_id": "518145",
-      "name": "6 入学时间",
-      "font_class": "6ruxueshijian",
-      "unicode": "e88a",
-      "unicode_decimal": 59530
-    },
-    {
-      "icon_id": "16365912",
-      "name": "专业 专业课",
-      "font_class": "zhuanyezhuanyeke",
-      "unicode": "e6a1",
-      "unicode_decimal": 59041
-    },
-    {
-      "icon_id": "376346",
-      "name": "工作单位",
-      "font_class": "commpany",
-      "unicode": "e612",
-      "unicode_decimal": 58898
-    },
-    {
-      "icon_id": "11672365",
-      "name": "职务管理",
-      "font_class": "zhiwuguanli",
-      "unicode": "e60f",
-      "unicode_decimal": 58895
-    },
-    {
-      "icon_id": "8712978",
-      "name": "关注",
-      "font_class": "guanzhu",
-      "unicode": "e611",
-      "unicode_decimal": 58897
-    },
-    {
-      "icon_id": "9714399",
-      "name": "关注",
-      "font_class": "guanzhu1",
-      "unicode": "e600",
-      "unicode_decimal": 58880
-    },
-    {
-      "icon_id": "6119296",
-      "name": "学历",
-      "font_class": "edu-line",
-      "unicode": "e63a",
-      "unicode_decimal": 58938
-    },
-    {
-      "icon_id": "6183156",
-      "name": "性别",
-      "font_class": "gender",
-      "unicode": "e63e",
-      "unicode_decimal": 58942
-    },
-    {
-      "icon_id": "20764666",
-      "name": "姓名",
-      "font_class": "xingming",
-      "unicode": "e640",
-      "unicode_decimal": 58944
-    },
-    {
-      "icon_id": "6856906",
-      "name": "基本信息",
-      "font_class": "jibenxinxi",
-      "unicode": "e67c",
-      "unicode_decimal": 59004
-    },
-    {
-      "icon_id": "1048854",
-      "name": "被关注",
-      "font_class": "iocn_be_concern",
-      "unicode": "e607",
-      "unicode_decimal": 58887
-    },
-    {
-      "icon_id": "2506206",
-      "name": "图片上传",
-      "font_class": "tupianshangchuan",
-      "unicode": "e639",
-      "unicode_decimal": 58937
-    },
-    {
-      "icon_id": "11372718",
-      "name": "我的关注",
-      "font_class": "wodeguanzhu",
-      "unicode": "e8bc",
-      "unicode_decimal": 59580
-    }
-  ]
-}

BIN
src/assets/icon/iconfont.ttf


BIN
src/assets/icon/iconfont.woff


BIN
src/assets/icon/iconfont.woff2


+ 153 - 0
src/components/custom/custom-form.vue

@@ -0,0 +1,153 @@
+<template>
+  <div id="custom-form">
+    <el-form ref="formRef" :model="form" :rules="rules" :label-width="labelWidth" class="form" @submit.prevent :disabled="disabled">
+      <el-col :span="span" v-for="(item, index) in fields" :key="index">
+        <el-form-item v-if="display(item)" :key="`form-field-${item.model}`" :label="getField('label', item)" :prop="item.model" :required="item.required">
+          <template v-if="item.custom">
+            <slot :name="item.model" v-bind="{ item }"></slot>
+          </template>
+          <template v-else>
+            <template v-if="item.type === 'textarea'">
+              <el-input clearable v-model="form[item.model]" :type="item.type" :placeholder="getField('placeholder', item)" v-bind="item.options" @change="dataChange(item.model)" show-word-limit></el-input>
+            </template>
+            <template v-else-if="item.type === 'numbers'">
+              <el-input-number v-model="form[item.model]" :placeholder="getField('placeholder', item)" @change="dataChange(item.model)" style="width: 100%" />
+            </template>
+            <template v-else-if="item.type === 'radio'">
+              <el-radio-group v-model="form[item.model]" :type="item.type" v-bind="item.options" @change="dataChange(item.model)">
+                <slot :name="item.model" v-bind="{ item }"></slot>
+              </el-radio-group>
+            </template>
+            <template v-else-if="item.type === 'checkbox'">
+              <el-checkbox-group v-model="form[item.model]" :type="item.type" v-bind="item.options">
+                <slot :name="item.model" v-bind="{ item }"></slot>
+              </el-checkbox-group>
+            </template>
+            <template v-else-if="item.type === 'select'">
+              <el-tooltip effect="dark" content="可输入文本搜索选项" placement="top-start">
+                <el-select clearable filterable allow-create default-first-option v-model="form[item.model]" :type="item.type" :placeholder="getField('selectplaceholder', item)" v-bind="item.options" @change="dataChange(item.model)" style="width: 100%">
+                  <slot :name="item.model" v-bind="{ item }"></slot>
+                </el-select>
+              </el-tooltip>
+            </template>
+            <template v-else-if="item.type === 'selectMany'">
+              <el-tooltip effect="dark" content="可输入文本搜索选项" placement="top-start">
+                <el-select filterable clearable multiple collapse-tags v-model="form[item.model]" :type="item.type" :placeholder="getField('selectplaceholder', item)" v-bind="item.options" @change="dataChange(item.model)" style="width: 100%">
+                  <slot :name="item.model" v-bind="{ item }"></slot>
+                </el-select>
+              </el-tooltip>
+            </template>
+            <template v-else-if="item.type === `year` || item.type == 'month' || item.type == 'date' || item.type == 'daterange' || item.type == 'datetime' || item.type == 'datetimerange'">
+              <el-date-picker v-model="form[item.model]" :type="item.type" :placeholder="getField('selectplaceholder', item)" :format="getDateFormat(item.type)" :value-format="getDateFormat(item.type)" v-bind="item.options" @change="dataChange(item.model)" range-separator="至" style="width: 100%"> </el-date-picker>
+            </template>
+            <template v-else-if="item.type === `time`">
+              <el-time-picker v-model="form[item.model]" :placeholder="getField('selectplaceholder', item)" :format="getDateFormat(item.type)" :value-format="getDateFormat(item.type)" v-bind="item.options" @change="dataChange(item.model)" style="width: 100%"> </el-time-picker>
+            </template>
+            <template v-else-if="item.type === `inputnumber`">
+              <el-input-number v-model="form[item.model]" :placeholder="getField('placeholder', item)" v-bind="item.options" @change="dataChange(item.model)" style="width: 100%"></el-input-number>
+            </template>
+            <template v-else>
+              <el-input clearable v-model="form[item.model]" :type="getField('type', item)" :placeholder="getField('placeholder', item)" :show-password="getField('type', item) === 'password'" v-bind="item.options" @change="dataChange(item.model)"></el-input>
+            </template>
+          </template>
+        </el-form-item>
+      </el-col>
+      <el-col :span="24" label="" class="btn" v-if="useSave">
+        <slot name="submit">
+          <el-button type="warning" @click="draftSave(formRef)">{{ submitDraft || '保存草稿' }}</el-button>
+          <el-button type="primary" @click="save(formRef)">{{ submitText || '保存并提交审核' }}</el-button>
+        </slot>
+      </el-col>
+    </el-form>
+  </div>
+</template>
+
+<script setup>
+import { get, isFunction } from 'lodash-es'
+const props = defineProps({
+  modelValue: { type: Object },
+  rules: { type: Array, default: () => {} },
+  labelWidth: { type: String, default: 'auto' },
+  disabled: { type: Boolean, default: false },
+  fields: { type: Array, default: () => [] },
+  submitText: { type: String },
+  submitDraft: { type: String },
+  useSave: { type: Boolean, default: true },
+  span: { type: Number, default: 24 } // 限制两侧的距离,24就是整行全用
+})
+const emits = defineEmits(['update:modelValue', 'dataChange', 'save', 'draftSave'])
+const formRef = ref()
+const form = computed({
+  get() {
+    return props.modelValue
+  },
+  set(value) {
+    console.log(value)
+    emits('update:modelValue', value)
+  }
+})
+const save = async (formEl) => {
+  if (!formEl) return
+  await formEl.validate((valid, fields) => {
+    if (valid) {
+      ElMessageBox.confirm(`您确认保存并提交审核该数据?`, '提示', { confirmButtonText: '确定', cancelButtonText: '取消', type: 'warning' })
+        .then(async () => {
+          emits('save', form.value)
+        })
+        .catch(() => {})
+    } else {
+      console.log('error submit!', fields)
+    }
+  })
+}
+const draftSave = async (formEl) => {
+  if (!formEl) return
+  await formEl.validate((valid, fields) => {
+    if (valid) {
+      emits('draftSave', form.value)
+    } else {
+      console.log('error submit!', fields)
+    }
+  })
+}
+const getField = (item, data) => {
+  let res = get(data, item, null)
+  if (item === 'type') res = res === null ? `text` : res
+  if (item === 'placeholder') res = res === null ? `请输入${data.label}` : res
+  if (item === `selectplaceholder`) res = res === null ? `请选择${data.label}` : res
+  if (item === 'required') res = res === null ? false : res
+  if (item === `error`) res = res === null ? `${data.label}错误` : res
+  return res
+}
+const dataChange = (model) => {
+  const value = form.value[model]
+  emits('dataChange', { model, value })
+}
+const display = (field) => {
+  let dis = get(field, `display`)
+  if (!isFunction(dis)) return true
+  else {
+    return dis(field, form)
+  }
+}
+const getDateFormat = (e) => {
+  if (e === 'year') return 'YYYY'
+  if (e === 'month') return 'MM'
+  if (e === 'date') return 'YYYY-MM-DD'
+  if (e === 'daterange') return 'YYYY-MM-DD'
+  if (e === 'datetime') return 'YYYY-MM-DD HH:mm:ss'
+  if (e === 'datetimerange') return 'YYYY-MM-DD HH:mm:ss'
+  if (e === 'time') return 'HH:mm:ss'
+}
+</script>
+<style scoped>
+.btn {
+  text-align: center;
+}
+
+.form {
+  display: flex;
+  flex-direction: row;
+  flex-wrap: wrap;
+}
+</style>

+ 186 - 0
src/layout/index.vue

@@ -0,0 +1,186 @@
+<template>
+  <div class="index">
+    <el-row>
+      <el-col :span="24" class="main animate__animated animate__backInRight" v-loading="loading">
+        <div class="left">
+          <div class="left_1" @click="toHome">
+            <el-image class="image" v-if="configInfo && configInfo.logoUrl && configInfo.logoUrl.length > 0" :src="getUrl(configInfo.logoUrl)" fit="fill" />
+            <el-image class="image" v-else :src="siteInfo.logoUrl" fit="fill" />
+            <div class="left_title">{{ configInfo.zhTitle || siteInfo.zhTitle }}</div>
+          </div>
+          <div class="left_2">
+            <div class="menus" :class="[item.route_name == acitveKey ? 'menuTrue' : '']" v-for="item in menuList3" :key="item.id" @click="toActive(item)">
+              <component class="icon" :is="item.icon"></component>
+              <span class="name">{{ item.name }}</span>
+            </div>
+          </div>
+        </div>
+        <div class="right">
+          <div class="right_1">
+            <div class="name">{{ user.nick_name || '暂无昵称' }}</div>
+            <div class="layout" @click="toOut">
+              <LoginOutlined />
+              <span>退出</span>
+            </div>
+          </div>
+          <div class="right_2">
+            <router-view></router-view>
+          </div>
+        </div>
+      </el-col>
+    </el-row>
+  </div>
+</template>
+
+<script setup>
+import { LoginOutlined } from '@ant-design/icons-vue'
+import { siteInfo, menuList3 } from '@/layout/site'
+// 接口
+import { DesignStore } from '@/store/api/platform/design'
+const designStore = DesignStore()
+
+import { UserStore } from '@/store/user'
+const userStore = UserStore()
+const user = computed(() => userStore.user)
+// 加载中
+const loading = ref(false)
+// 路由
+const router = useRouter()
+const route = useRoute()
+
+const acitveKey = ref(route.name)
+
+const $checkRes = inject('$checkRes')
+const configInfo = ref({})
+
+// 请求
+onMounted(async () => {
+  await searchOther()
+})
+const searchOther = async () => {
+  // 基础设置
+  const result = await designStore.query({})
+  if ($checkRes(result)) {
+    configInfo.value = result.data[0] || {}
+  }
+}
+const toActive = async (item) => {
+  acitveKey.value = item.route_name
+  router.push({ path: item.path })
+}
+// 退出登录
+const toOut = () => {
+  userStore.logOut()
+  router.push({ path: '/login', query: { status: '1' } })
+}
+// 返回首页
+const toHome = () => {
+  router.push({ path: `/` })
+}
+const getUrl = (item) => {
+  if (item && item.length > 0) return `${import.meta.env.VITE_APP_HOST}${item[0].uri}`
+}
+watch(
+  route,
+  (newVal) => {
+    if (newVal && newVal.name) acitveKey.value = newVal.name
+  },
+  {
+    immediate: true //初始化立即执行
+  }
+)
+</script>
+<style scoped lang="scss">
+.main {
+  display: flex;
+  background: #f1f6f9;
+  min-height: 100vh;
+  .left {
+    width: 20%;
+    background: linear-gradient(180deg, #165aa0, #4942dd);
+    height: 100%;
+    border-top-right-radius: 40px;
+    border-bottom-right-radius: 40px;
+    .left_1 {
+      cursor: default;
+      padding-top: 20px;
+      padding-left: 10px;
+      padding-right: 10px;
+      color: #ffffff;
+      display: flex;
+      flex-direction: column;
+      align-items: center;
+      .image {
+        height: 60px;
+        width: 220px;
+      }
+      .left_title {
+        padding: 10px 0 0 0;
+        font-size: $global-font-size-24;
+        font-family: 'Comic Sans MS', cursive;
+      }
+    }
+    .left_2 {
+      padding-left: 15px;
+      padding-top: 35px;
+      .menus {
+        font-size: $global-font-size-20;
+        font-weight: 500;
+        color: #fff;
+        height: 67px;
+        line-height: 67px;
+        padding-left: 80px;
+        border-bottom-left-radius: 33px;
+        border-top-left-radius: 33px;
+        position: relative;
+        cursor: pointer;
+        .icon {
+          display: inline-block;
+          width: 1em;
+          height: 1em;
+          overflow: hidden;
+          vertical-align: -0.15em;
+          outline: none;
+          margin-right: 5px;
+        }
+      }
+      .menuTrue {
+        background: #f1f6f9;
+        color: #3961aa;
+      }
+      .menuTrue:after {
+        content: url(/images/center_1.png);
+        position: absolute;
+        right: 0;
+        top: -43px;
+      }
+    }
+  }
+  .right {
+    width: 80%;
+    padding: 0 20px;
+    .right_1 {
+      display: flex;
+      justify-content: flex-end;
+      height: 80px;
+      line-height: 80px;
+      font-size: $global-font-size-20;
+      .layout {
+        padding: 0 10px 0 20px;
+        color: #8a8b8c;
+        cursor: pointer;
+        span {
+          margin: 0 0 0 5px;
+        }
+      }
+    }
+    .right_2 {
+      width: 100%;
+      min-height: 90vh;
+      background: #fff;
+      border-radius: 10px;
+      padding: 20px;
+    }
+  }
+}
+</style>

+ 10 - 0
src/layout/site.js

@@ -138,3 +138,13 @@ export const menuList2 = [
   { key: '12', title: '产业孵化大脑', route: 'brain', English: 'Achievement Display', label: '产业孵化大脑' },
   { key: '13', title: '行研产研', route: 'thirteen', English: 'Research Development', label: '行研产研' }
 ]
+// 目录设置
+export const menuList3 = [
+  { id: 1, name: '基本信息', route_name: 'center', path: '/center', icon: 'User' },
+  { id: 2, name: '认证入驻', route_name: 'attestation', path: '/attestation', icon: 'Finished' },
+  { id: 3, name: '通知管理', route_name: 'notice', path: '/notice', icon: 'Notebook' },
+  { id: 4, name: '成果管理', route_name: 'achievement', path: '/achievement', icon: 'Medal' },
+  { id: 5, name: '需求管理', route_name: 'demand', path: '/demand', icon: 'DataBoard' },
+  { id: 6, name: '我的收藏', route_name: 'collect', path: '/collect', icon: 'Collection' },
+  { id: 7, name: '活动管理', route_name: 'match', path: '/match', icon: 'Suitcase' }
+]

+ 48 - 4
src/router/index.js

@@ -1,5 +1,6 @@
 import { createRouter, createWebHistory } from 'vue-router'
 import { UserStore } from '@/store/user'
+export const Layout = () => import('@/layout/index.vue')
 import axios from 'axios'
 const router = createRouter({
   history: createWebHistory(import.meta.env.BASE_URL),
@@ -248,10 +249,53 @@ const router = createRouter({
       component: () => import('@/views/search/index.vue')
     },
     {
-      path: '/center',
-      name: 'center',
-      meta: { title: '产学研用协同创新数字化平台-个人中心' },
-      component: () => import('@/views/center/index.vue')
+      path: '/layout',
+      name: 'Layout',
+      component: Layout,
+      children: [
+        {
+          path: '/center',
+          name: 'center',
+          meta: { title: '产学研用协同创新数字化平台-基本信息' },
+          component: () => import('@/views/center/basic.vue')
+        },
+        {
+          path: '/attestation',
+          name: 'attestation',
+          meta: { title: '产学研用协同创新数字化平台-认证入驻' },
+          component: () => import('@/views/center/attestation.vue')
+        },
+        {
+          path: '/notice',
+          name: 'notice',
+          meta: { title: '产学研用协同创新数字化平台-通知管理' },
+          component: () => import('@/views/center/notice.vue')
+        },
+        {
+          path: '/achievement',
+          name: 'achievement',
+          meta: { title: '产学研用协同创新数字化平台-成果管理' },
+          component: () => import('@/views/center/achievement.vue')
+        },
+        {
+          path: '/demand',
+          name: 'demand',
+          meta: { title: '产学研用协同创新数字化平台-需求管理' },
+          component: () => import('@/views/center/demand.vue')
+        },
+        {
+          path: '/collect',
+          name: 'collect',
+          meta: { title: '产学研用协同创新数字化平台-我的收藏' },
+          component: () => import('@/views/center/collect.vue')
+        },
+        {
+          path: '/match',
+          name: 'match',
+          meta: { title: '产学研用协同创新数字化平台-活动管理' },
+          component: () => import('@/views/center/match.vue')
+        }
+      ]
     },
     {
       path: '/loading',

+ 310 - 0
src/views/center/achievement.vue

@@ -0,0 +1,310 @@
+<template>
+  <div class="index">
+    <el-row>
+      <el-col :span="24" class="main animate__animated animate__backInRight" v-loading="loading">
+        <el-col :span="24" class="one">
+          <div class="one_left" @click="toAdd">发布成果</div>
+          <div class="one_right">
+            <el-input v-model="searchForm.name" style="width: 250px" size="large" placeholder="搜索" @change="search" :suffix-icon="Search" />
+          </div>
+        </el-col>
+        <el-col :span="24" class="two">
+          <el-table :data="list" style="width: 100%" size="large" :header-cell-style="{ backgroundColor: '#edf3ff' }">
+            <template #empty>
+              <el-empty description="暂无数据" />
+            </template>
+            <el-table-column prop="name" align="center" label="成果名称" />
+            <el-table-column prop="time" align="center" label="发布时间" width="180" />
+            <el-table-column prop="status" align="center" label="状态" width="180">
+              <template #default="scope">
+                <div>{{ getDict(scope.row.status, 'status') }}</div>
+              </template>
+            </el-table-column>
+            <el-table-column align="center" label="操作" width="180">
+              <template #default="{ row }">
+                <el-link v-if="row.status == '-2'" :underline="false" type="warning" size="mini" @click="toExam(row)" style="margin-right: 10px">提交审核</el-link>
+                <el-link :underline="false" type="primary" size="mini" @click="toEdit(row)" style="margin-right: 10px">修改</el-link>
+                <el-link :underline="false" type="danger" size="mini" @click="toDelete(row)"> 删除 </el-link>
+              </template>
+            </el-table-column>
+          </el-table>
+        </el-col>
+        <el-col :span="24" class="thr">
+          <el-pagination background layout="prev, pager, next" :total="total" :page-size="limit" v-model:current-page="currentPage" @current-change="changePage" @size-change="sizeChange" />
+        </el-col>
+      </el-col>
+    </el-row>
+    <el-dialog v-model="dialog.show" :title="dialog.title" :destroy-on-close="false" @close="toClose">
+      <el-row>
+        <el-col :span="24" v-if="dialog.type == '1'">
+          <custom-form v-model="form" :fields="formFields" :rules="rules" @save="toSave" @draftSave="toDraftSave">
+            <template #is_use>
+              <el-radio v-for="i in isUseList" :key="i.id" :label="i.value">{{ i.label }}</el-radio>
+            </template>
+            <template #field>
+              <el-option v-for="i in fieldList" :key="i.id" :label="i.label" :value="i.label"></el-option>
+            </template>
+            <template #attribute>
+              <el-option v-for="i in attributeList" :key="i.id" :label="i.label" :value="i.value"></el-option>
+            </template>
+            <template #mature>
+              <el-option v-for="i in matureList" :key="i.id" :label="i.label" :value="i.value"></el-option>
+            </template>
+            <template #sell>
+              <el-option v-for="i in sellList" :key="i.id" :label="i.label" :value="i.value"></el-option>
+            </template>
+            <template #technology>
+              <el-option v-for="i in technologyList" :key="i.id" :label="i.label" :value="i.value"></el-option>
+            </template>
+            <template #area>
+              <el-cascader v-model="form.area" :props="{ value: 'name', label: 'name' }" :options="cityList" style="width: 100%" />
+            </template>
+            <template #file>
+              <custom-upload model="file" :list="form.file" :limit="1" url="/files/web/cxyy_achievement/upload" @change="onUpload"></custom-upload>
+            </template>
+            <template #industry>
+              <el-option v-for="i in sectorList" :key="i.id" :label="i.title" :value="i.title"></el-option>
+            </template>
+            <template #tags>
+              <el-select v-model="form.tags" multiple filterable allow-create default-first-option :reserve-keyword="false" placeholder="请选择标签" style="width: 100%">
+                <el-option v-for="item in tagsList" :key="item.id" :label="item.title" :value="item.title" />
+              </el-select>
+            </template>
+          </custom-form>
+        </el-col>
+      </el-row>
+    </el-dialog>
+  </div>
+</template>
+
+<script setup>
+import { Search } from '@element-plus/icons-vue'
+import { cloneDeep, get } from 'lodash-es'
+const $checkRes = inject('$checkRes')
+import { UserStore } from '@/store/user'
+const userStore = UserStore()
+const user = computed(() => userStore.user)
+// 接口
+import { AchievementStore } from '@/store/api/platform/achievement'
+import { DictDataStore } from '@/store/api/system/dictData'
+import { TagsStore } from '@/store/api/system/tags'
+import { SectorStore } from '@/store/api/platform/sector'
+import { RegionStore } from '@/store/api/system/region'
+const regionStore = RegionStore()
+const store = AchievementStore()
+const dictDataStore = DictDataStore()
+const tagsStore = TagsStore()
+const sectorStore = SectorStore()
+// 加载中
+const loading = ref(false)
+
+const searchForm = ref({})
+// 列表
+const list = ref([])
+let skip = 0
+let limit = inject('limit')
+const total = ref(0)
+const currentPage = ref(1)
+// 字典表
+const isUseList = ref([])
+const statusList = ref([])
+const fieldList = ref([])
+const attributeList = ref([])
+const matureList = ref([])
+const sellList = ref([])
+const technologyList = ref([])
+const cityList = ref([])
+const achievementList = ref([])
+const tagsList = ref([])
+const sectorList = ref([])
+
+const form = ref({ file: [] })
+const dialog = ref({ type: '1', show: false, title: '发布成果' })
+const formFields = ref([
+  { label: '成果名称', model: 'name' },
+  { label: '标签', model: 'tags', custom: true },
+  { label: '所属产业', model: 'industry', type: 'select' },
+  { label: '专利号', model: 'patent' },
+  { label: '行业领域', model: 'field' },
+  { label: '属性', model: 'attribute', type: 'select' },
+  { label: '成熟度', model: 'mature', type: 'select' },
+  { label: '出让方式', model: 'sell', type: 'select' },
+  { label: '技术分类', model: 'technology', type: 'select' },
+  { label: '成果地区', model: 'area', custom: true },
+  { label: '发布时间', model: 'time', type: 'date' },
+  { label: '价格(万元)', model: 'money' },
+  { label: '项目来源', model: 'source' },
+  { label: '联系人', model: 'person' },
+  { label: '联系电话', model: 'tel' },
+  { label: '是否公开', model: 'is_use', type: 'radio' },
+  { label: '简介', model: 'brief', type: 'textarea' },
+  { label: '附件', model: 'file', custom: true }
+])
+const rules = reactive({ name: [{ required: true, message: '请输入成果名称', trigger: 'blur' }] })
+// 请求
+onMounted(async () => {
+  loading.value = true
+  await searchOther()
+  await search()
+  loading.value = false
+})
+const search = async (query = { skip, limit }) => {
+  skip = query.skip
+  limit = query.limit
+  const info = {
+    skip: query.skip,
+    limit: query.limit,
+    user: user.value.id,
+    ...searchForm.value
+  }
+  const res = await store.list(info)
+  if (res.errcode == '0') {
+    list.value = res.data
+    total.value = res.total
+  }
+}
+const searchOther = async () => {
+  let result
+  // 是否使用
+  result = await dictDataStore.query({ code: 'isUse', is_use: '0' })
+  if ($checkRes(result)) isUseList.value = result.data
+  // 状态
+  result = await dictDataStore.query({ code: 'examStatus', is_use: '0' })
+  if ($checkRes(result)) statusList.value = result.data
+  // 成熟度
+  result = await dictDataStore.query({ code: 'mature', is_use: '0' })
+  if ($checkRes(result)) matureList.value = result.data
+  // 出让方式
+  result = await dictDataStore.query({ code: 'sell', is_use: '0' })
+  if ($checkRes(result)) sellList.value = result.data
+  // 技术领域
+  result = await dictDataStore.query({ code: 'field', is_use: '0' })
+  if ($checkRes(result)) fieldList.value = result.data
+  // 属性
+  result = await dictDataStore.query({ code: 'attribute', is_use: '0' })
+  if ($checkRes(result)) attributeList.value = result.data
+  // 技术分类
+  result = await dictDataStore.query({ code: 'technology', is_use: '0' })
+  if ($checkRes(result)) technologyList.value = result.data
+  // 成果状态
+  result = await dictDataStore.query({ code: 'demandStatus', is_use: '0' })
+  if ($checkRes(result)) achievementList.value = result.data
+  // 标签
+  result = await tagsStore.query({ is_use: '0' })
+  if ($checkRes(result)) tagsList.value = result.data
+  // 行业
+  result = await sectorStore.query({ is_use: '0' })
+  if ($checkRes(result)) sectorList.value = result.data
+  // 城市
+  result = await regionStore.area({ level: 'province', code: 22 })
+  if ($checkRes(result)) cityList.value = result.data
+}
+// 字典数据转换
+const getDict = (data, model) => {
+  if (data) {
+    let res
+    if (model == 'status') res = statusList.value.find((f) => f.value == data)
+    return get(res, 'label')
+  }
+}
+// 添加
+const toAdd = () => {
+  dialog.value = { type: '1', show: true, title: '发布成果' }
+}
+// 修改
+const toEdit = (data) => {
+  if (!data.file) data.file = []
+  form.value = data
+  dialog.value = { type: '1', show: true, title: '修改成果' }
+}
+// 删除
+const toDelete = (data) => {
+  ElMessageBox.confirm(`您确认删除${data.name}该数据?`, '提示', { confirmButtonText: '确定', cancelButtonText: '取消', type: 'warning' })
+    .then(async () => {
+      const res = await store.del(data.id)
+      if ($checkRes(res, true)) {
+        search({ skip, limit })
+      }
+    })
+    .catch(() => {})
+}
+// 上传图片
+const onUpload = (e) => {
+  const { model, value } = e
+  form.value[model] = value
+}
+const toSave = async () => {
+  const data = cloneDeep(form.value)
+  const other = { status: '0', user: user.value.id }
+  let res
+  if (get(data, 'id')) res = await store.update({ ...data, ...other })
+  else res = await store.create({ ...data, ...other })
+  if ($checkRes(res, true)) {
+    search({ skip, limit })
+    toClose()
+  }
+}
+const toDraftSave = async () => {
+  const data = cloneDeep(form.value)
+  const other = { status: '-2', user: user.value.id }
+  let res
+  if (get(data, 'id')) res = await store.update({ ...data, ...other })
+  else res = await store.create({ ...data, ...other })
+  if ($checkRes(res, true)) {
+    search({ skip, limit })
+    toClose()
+  }
+}
+// 审核保存
+const toExam = async (row) => {
+  ElMessageBox.confirm(`您确认保存并提交审核该数据?`, '提示', { confirmButtonText: '确定', cancelButtonText: '取消', type: 'warning' })
+    .then(async () => {
+      const data = cloneDeep(row)
+      let res = await store.update({ id: data.id, status: '0', user: user.value.id })
+      if ($checkRes(res, true)) {
+        search({ skip, limit })
+        toClose()
+      }
+    })
+    .catch(() => {})
+}
+const toClose = () => {
+  form.value = { file: [] }
+  dialog.value = { show: false }
+}
+// 分页
+const changePage = (page = currentPage.value) => {
+  search({ skip: (page - 1) * limit, limit: limit })
+}
+const sizeChange = (limits) => {
+  limit = limits
+  currentPage.value = 1
+  search({ skip: 0, limit: limit })
+}
+</script>
+<style scoped lang="scss">
+.main {
+  .one {
+    height: 50px;
+    display: flex;
+    justify-content: space-between;
+    align-items: center;
+    margin: 0 0 10px 0;
+    .one_left {
+      background: #1875df;
+      padding: 0 10px;
+      height: 30px;
+      color: #fff;
+      line-height: 30px;
+      text-align: center;
+      font-size: 16px;
+      cursor: default;
+    }
+  }
+  .thr {
+    display: flex;
+    justify-content: center;
+    margin: 20px 0 0 0;
+  }
+}
+</style>

+ 153 - 0
src/views/center/attestation.vue

@@ -0,0 +1,153 @@
+<template>
+  <div class="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 :span="24" class="two">
+          <el-tabs v-model="activeName" class="tabs">
+            <el-tab-pane :name="item.code" v-for="(item, index) in roleList" :key="index">
+              <template #label>
+                <span class="custom-tabs-label">
+                  <span>{{ item.title }}</span>
+                </span>
+              </template>
+            </el-tab-pane>
+          </el-tabs>
+        </el-col>
+        <el-col :span="24" class="thr">
+          <expert v-if="activeName == 'Expert'"></expert>
+          <company v-if="activeName == 'Company'"></company>
+          <incubator v-if="activeName == 'Incubator'"></incubator>
+          <competition v-if="activeName == 'Competition'"></competition>
+          <investment v-if="activeName == 'Investment'"></investment>
+          <association v-if="activeName == 'Association'"></association>
+          <state v-if="activeName == 'State'"></state>
+          <unit v-if="activeName == 'Unit'"></unit>
+        </el-col>
+      </el-col>
+    </el-row>
+  </div>
+</template>
+
+<script setup>
+import { cloneDeep } from 'lodash-es'
+
+const $checkRes = inject('$checkRes')
+import { UserStore } from '@/store/user'
+const userStore = UserStore()
+const user = computed(() => userStore.user)
+// 组件
+import association from './parts/association.vue'
+import company from './parts/company.vue'
+import competition from './parts/competition.vue'
+import expert from './parts/expert.vue'
+import incubator from './parts/incubator.vue'
+import state from './parts/state.vue'
+import unit from './parts/unit.vue'
+import investment from './parts/investment.vue'
+
+// 接口
+import { RoleStore } from '@/store/api/system/role'
+const roleStore = RoleStore()
+import { DictDataStore } from '@/store/api/system/dictData'
+import { RegionStore } from '@/store/api/system/region'
+const dictDataStore = DictDataStore()
+const regionStore = RegionStore()
+
+const activeName = ref('')
+// 加载中
+const loading = ref(false)
+// 字典
+const roleList = ref([])
+const typeList = ref([])
+const genderList = ref([])
+const fieldList = ref([])
+const educationList = ref([])
+const cityList = ref([])
+const isUseList = ref([])
+const patternList = ref([])
+const scaleList = ref([])
+const IndustryList = ref([])
+const cardTypeList = ref([])
+const contributionList = ref([])
+// 请求
+onMounted(async () => {
+  loading.value = true
+  await searchOther()
+  loading.value = false
+})
+const searchOther = async () => {
+  let result
+  // 角色
+  result = await roleStore.query({ is_use: '0' })
+  if ($checkRes(result)) {
+    activeName.value = result.data[0].code
+    const list = []
+    for (const val of result.data) {
+      const role = user.value.role.find((i) => i == val.code)
+      if (role) val.title = `${val.name}(已认证)`
+      else val.title = `${val.name}(未认证)`
+      if (val.code != 'Admin' && val.code != 'User') list.push(val)
+    }
+    roleList.value = list
+  }
+  // 性别
+  result = await dictDataStore.query({ code: 'gender', is_use: '0' })
+  if ($checkRes(result)) genderList.value = result.data
+  // 用户类型
+  result = await dictDataStore.query({ code: 'userType', is_use: '0' })
+  if ($checkRes(result)) typeList.value = result.data
+  // 专家领域
+  result = await dictDataStore.query({ code: 'field', is_use: '0' })
+  if ($checkRes(result)) fieldList.value = result.data
+  // 企业类型
+  result = await dictDataStore.query({ code: 'companyType', is_use: '0' })
+  if ($checkRes(result)) patternList.value = result.data
+  // 企业规模
+  result = await dictDataStore.query({ code: 'companyScale', is_use: '0' })
+  if ($checkRes(result)) scaleList.value = result.data
+  // 企业所属行业
+  result = await dictDataStore.query({ code: 'companyIndustry', is_use: '0' })
+  if ($checkRes(result)) IndustryList.value = result.data
+  // 学历
+  result = await dictDataStore.query({ code: 'education', is_use: '0' })
+  if ($checkRes(result)) educationList.value = result.data
+  // 证件类型
+  result = await dictDataStore.query({ code: 'cardType', is_use: '0' })
+  if ($checkRes(result)) cardTypeList.value = result.data
+  // 出资方式
+  result = await dictDataStore.query({ code: 'contribution', is_use: '0' })
+  if ($checkRes(result)) contributionList.value = result.data
+  // 是否使用
+  result = await dictDataStore.query({ code: 'isUse', is_use: '0' })
+  if ($checkRes(result)) isUseList.value = result.data
+  // 城市
+  result = await regionStore.area({ level: 'province', code: 22 })
+  if ($checkRes(result)) cityList.value = result.data
+}
+// provide
+provide('cloneDeep', cloneDeep)
+// 字典
+provide('genderList', genderList)
+provide('fieldList', fieldList)
+provide('educationList', educationList)
+provide('cityList', cityList)
+provide('isUseList', isUseList)
+provide('patternList', patternList)
+provide('scaleList', scaleList)
+provide('IndustryList', IndustryList)
+provide('cardTypeList', cardTypeList)
+provide('contributionList', contributionList)
+</script>
+<style scoped lang="scss">
+.main {
+  .one {
+    font-size: $global-font-size-20;
+    font-weight: 700;
+    margin: 0 0 20px 0;
+  }
+  .thr {
+    padding: 20px;
+  }
+}
+</style>

+ 156 - 0
src/views/center/basic.vue

@@ -0,0 +1,156 @@
+<template>
+  <div class="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 :span="24" class="two">
+          <el-form label-position="top" ref="ruleFormRef" :model="form" :rules="rules" label-width="80px" class="form">
+            <el-form-item label="账号" prop="account">
+              <el-input size="large" clearable disabled v-model="form.account" placeholder="请输入账号">
+                <template #prefix>
+                  <el-icon>
+                    <User />
+                  </el-icon>
+                </template>
+              </el-input>
+            </el-form-item>
+            <el-form-item label="板块选择" prop="industry">
+              <el-checkbox-group v-model="form.industry">
+                <el-checkbox v-for="(item, index) in plateList" :key="index" :value="item.title" name="type">{{ item.title }}</el-checkbox>
+              </el-checkbox-group>
+            </el-form-item>
+            <el-form-item label="昵称" prop="nick_name">
+              <el-input size="large" clearable v-model="form.nick_name" placeholder="请输入昵称">
+                <template #prefix>
+                  <el-icon>
+                    <Avatar />
+                  </el-icon>
+                </template>
+              </el-input>
+            </el-form-item>
+            <el-form-item label="性别" prop="gender">
+              <el-select size="large" v-model="form.gender" width="100%" placeholder="请选择性别">
+                <el-option v-for="(item, index) in genderList" :key="index" :label="item.label" :value="item.value" />
+              </el-select>
+            </el-form-item>
+            <el-form-item label="手机号" prop="phone">
+              <el-input size="large" clearable v-model="form.phone" placeholder="请输入手机号">
+                <template #prefix>
+                  <el-icon>
+                    <Iphone />
+                  </el-icon>
+                </template>
+              </el-input>
+            </el-form-item>
+            <el-form-item label="电子邮箱" prop="email">
+              <el-input size="large" clearable v-model="form.email" placeholder="请填入正确的电子邮箱">
+                <template #prefix>
+                  <el-icon>
+                    <Message />
+                  </el-icon>
+                </template>
+              </el-input>
+            </el-form-item>
+            <el-col :span="24" class="button">
+              <el-button type="primary" @click="submitForm(ruleFormRef)">保存</el-button>
+            </el-col>
+          </el-form>
+        </el-col>
+      </el-col>
+    </el-row>
+  </div>
+</template>
+
+<script setup>
+import { cloneDeep } from 'lodash-es'
+import { UserStore } from '@/store/user'
+const userStore = UserStore()
+const user = computed(() => userStore.user)
+import { UsersStore } from '@/store/api/user/user'
+import { DictDataStore } from '@/store/api/system/dictData'
+import { SectorStore } from '@/store/api/platform/sector'
+const store = UsersStore()
+const dictDataStore = DictDataStore()
+const sectorStore = SectorStore()
+const $checkRes = inject('$checkRes')
+const form = ref({})
+// 表单验证
+const ruleFormRef = ref()
+const validatePhoneNumber = (rule, value, callback) => {
+  const reg = /^1[3-9]\d{9}$/
+  if (!value) {
+    return callback(new Error('手机号不能为空'))
+  }
+  if (!reg.test(value)) {
+    return callback(new Error('请输入正确的手机号'))
+  }
+  callback()
+}
+const rules = reactive({
+  nick_name: [{ required: true, message: '请输入昵称', trigger: 'blur' }],
+  gender: [{ required: true, message: '请选择性别', trigger: 'blur' }],
+  phone: [{ required: true, validator: validatePhoneNumber, trigger: 'blur' }],
+  email: [{ required: true, message: '请输入电子邮箱', trigger: 'blur' }],
+  account: [{ required: true, message: '请输入账号', trigger: 'blur' }],
+  industry: [{ required: true, message: '请选择板块', trigger: 'blur' }]
+})
+// 加载中
+const loading = ref(false)
+// 字典
+const genderList = ref([])
+const plateList = ref([])
+// 请求
+onMounted(async () => {
+  loading.value = true
+  await searchOther()
+  await search()
+  loading.value = false
+})
+const search = async () => {
+  if (user.value.id) {
+    let res = await store.detail(user.value.id)
+    if (res.errcode == '0') {
+      if (res.data.industry) res.data.industry = [res.data.industry]
+      form.value = res.data
+    }
+  }
+}
+const searchOther = async () => {
+  let result
+  // 性别
+  result = await dictDataStore.query({ code: 'gender', is_use: '0' })
+  if ($checkRes(result)) genderList.value = result.data
+  // 板块
+  result = await sectorStore.query({ is_use: '0' })
+  if ($checkRes(result)) plateList.value = result.data
+}
+// 保存
+const submitForm = async (ruleFormRef) => {
+  if (!ruleFormRef) return
+  await ruleFormRef.validate(async (valid, fields) => {
+    if (valid) {
+      const data = cloneDeep(form.value)
+      if (data.industry) data.industry = data.industry[0]
+      const res = await store.update(data)
+      if ($checkRes(res, true)) search()
+    } else {
+      console.log('error submit!', fields)
+    }
+  })
+}
+</script>
+<style scoped lang="scss">
+.main {
+  .one {
+    font-size: $global-font-size-20;
+    font-weight: 700;
+    margin: 0 0 20px 0;
+  }
+  .two {
+    .button {
+      margin: 10px 0 0 0;
+      text-align: center;
+    }
+  }
+}
+</style>

+ 145 - 0
src/views/center/collect.vue

@@ -0,0 +1,145 @@
+<template>
+  <div class="index">
+    <el-row>
+      <el-col :span="24" class="main animate__animated animate__backInRight" v-loading="loading">
+        <el-col :span="24" class="one">
+          <div class="one_left">
+            <span>收藏分类</span>
+            <el-select v-model="searchForm.type" placeholder="请选择" style="width: 240px">
+              <el-option v-for="item in typeList" :key="item.value" :label="item.label" :value="item.value" />
+            </el-select>
+          </div>
+          <div class="one_right">
+            <el-input v-model="searchForm.name" style="width: 250px" size="large" placeholder="搜索" @change="search" :suffix-icon="Search" />
+          </div>
+        </el-col>
+        <el-col :span="24" class="two">
+          <el-table :data="list" style="width: 100%" size="large" :header-cell-style="{ backgroundColor: '#edf3ff' }">
+            <template #empty>
+              <el-empty description="暂无数据" />
+            </template>
+            <el-table-column prop="name" align="center" label="需求名称" />
+            <el-table-column prop="created_time" align="center" label="发布时间" width="180" />
+            <el-table-column prop="status" align="center" label="状态" width="180">
+              <template #default="scope">
+                <div>{{ getDict(scope.row.status, 'status') }}</div>
+              </template>
+            </el-table-column>
+            <el-table-column align="center" label="操作" width="180">
+              <template #default="{ row }">
+                <el-link :underline="false" type="primary" size="mini" @click="toEdit(row)" style="margin-right: 10px">修改</el-link>
+                <el-link :underline="false" type="danger" size="mini" @click="toDelete(row)"> 删除 </el-link>
+              </template>
+            </el-table-column>
+          </el-table>
+        </el-col>
+        <el-col :span="24" class="thr">
+          <el-pagination background layout="prev, pager, next" :total="total" :page-size="limit" v-model:current-page="currentPage" @current-change="changePage" @size-change="sizeChange" />
+        </el-col>
+      </el-col>
+    </el-row>
+  </div>
+</template>
+
+<script setup>
+import { Search } from '@element-plus/icons-vue'
+import { get } from 'lodash-es'
+const $checkRes = inject('$checkRes')
+import { UserStore } from '@/store/user'
+const userStore = UserStore()
+const user = computed(() => userStore.user)
+// 接口
+import { DemandStore } from '@/store/api/platform/demand'
+const store = DemandStore()
+import { DictDataStore } from '@/store/api/system/dictData'
+const dictDataStore = DictDataStore()
+// 加载中
+const loading = ref(false)
+// 列表
+const list = ref([])
+let skip = 0
+let limit = inject('limit')
+const total = ref(0)
+const currentPage = ref(1)
+const searchForm = ref({})
+// 字典表
+const statusList = ref([])
+const typeList = ref([
+  { value: '1', label: '全部' },
+  { value: '2', label: '需求' },
+  { value: '3', label: '成果' },
+  { value: '4', label: '项目' },
+  { value: '5', label: '专家' },
+  { value: '5', label: '企业' }
+])
+// 请求
+onMounted(async () => {
+  loading.value = true
+  await searchOther()
+  await search()
+  loading.value = false
+})
+const search = async (query = { skip, limit }) => {
+  // skip = query.skip
+  // limit = query.limit
+  // const info = {
+  //   skip: query.skip,
+  //   limit: query.limit,
+  //   user: user.value.id,
+  // ...searchForm.value
+  // }
+  // const res = await store.list(info)
+  // if (res.errcode == '0') {
+  //   list.value = res.data
+  //   total.value = res.total
+  // }
+}
+const searchOther = async () => {
+  let result
+  // 状态
+  result = await dictDataStore.query({ code: 'examStatus', is_use: '0' })
+  if ($checkRes(result)) statusList.value = result.data
+}
+// 字典数据转换
+const getDict = (data, model) => {
+  if (data) {
+    let res
+    if (model == 'status') res = statusList.value.find((f) => f.value == data)
+    return get(res, 'label')
+  }
+}
+// 分页
+const changePage = (page = currentPage.value) => {
+  search({ skip: (page - 1) * limit, limit: limit })
+}
+const sizeChange = (limits) => {
+  limit = limits
+  currentPage.value = 1
+  search({ skip: 0, limit: limit })
+}
+</script>
+<style scoped lang="scss">
+.main {
+  .one {
+    height: 50px;
+    display: flex;
+    justify-content: space-between;
+    align-items: center;
+    margin: 0 0 10px 0;
+    .one_left {
+      display: flex;
+      align-items: center;
+      span {
+        font-size: $global-font-size-16;
+        margin: 0 5px 0 0;
+        color: #606266;
+      }
+    }
+  }
+  .thr {
+    display: flex;
+    justify-content: center;
+    margin: 20px 0 0 0;
+  }
+}
+</style>

+ 300 - 0
src/views/center/demand.vue

@@ -0,0 +1,300 @@
+<template>
+  <div class="index">
+    <el-row>
+      <el-col :span="24" class="main animate__animated animate__backInRight" v-loading="loading">
+        <el-col :span="24" class="one">
+          <div class="one_left" @click="toAdd">发布需求</div>
+          <div class="one_right">
+            <el-input v-model="searchForm.name" style="width: 250px" size="large" placeholder="搜索" @change="search" :suffix-icon="Search" />
+          </div>
+        </el-col>
+        <el-col :span="24" class="two">
+          <el-table :data="list" style="width: 100%" size="large" :header-cell-style="{ backgroundColor: '#edf3ff' }">
+            <template #empty>
+              <el-empty description="暂无数据" />
+            </template>
+            <el-table-column prop="name" align="center" label="需求名称" />
+            <el-table-column prop="start_time" align="center" label="开始时间" width="180" />
+            <el-table-column prop="end_time" align="center" label="结束时间" width="180" />
+            <el-table-column prop="status" align="center" label="状态" width="180">
+              <template #default="scope">
+                <div>{{ getDict(scope.row.status, 'status') }}</div>
+              </template>
+            </el-table-column>
+            <el-table-column align="center" label="操作" width="180">
+              <template #default="{ row }">
+                <el-link v-if="row.status == '-2'" :underline="false" type="warning" size="mini" @click="toExam(row)" style="margin-right: 10px">提交审核</el-link>
+                <el-link :underline="false" type="primary" size="mini" @click="toEdit(row)" style="margin-right: 10px">修改</el-link>
+                <el-link :underline="false" type="danger" size="mini" @click="toDelete(row)"> 删除 </el-link>
+              </template>
+            </el-table-column>
+          </el-table>
+        </el-col>
+        <el-col :span="24" class="thr">
+          <el-pagination background layout="prev, pager, next" :total="total" :page-size="limit" v-model:current-page="currentPage" @current-change="changePage" @size-change="sizeChange" />
+        </el-col>
+      </el-col>
+    </el-row>
+    <el-dialog v-model="dialog.show" :title="dialog.title" :destroy-on-close="false" @close="toClose">
+      <el-row>
+        <el-col :span="24" v-if="dialog.type == '1'">
+          <custom-form v-model="form" :fields="formFields" :rules="rules" @save="toSave" @draftSave="toDraftSave">
+            <template #is_use>
+              <el-radio v-for="i in isUseList" :key="i.id" :label="i.value">{{ i.label }}</el-radio>
+            </template>
+            <template #field>
+              <el-option v-for="i in fieldList" :key="i.id" :label="i.label" :value="i.label"></el-option>
+            </template>
+            <template #industry>
+              <el-option v-for="i in sectorList" :key="i.id" :label="i.title" :value="i.title"></el-option>
+            </template>
+            <template #urgent>
+              <el-option v-for="i in urgentList" :key="i.id" :label="i.label" :value="i.value"></el-option>
+            </template>
+            <template #method>
+              <el-option v-for="i in methodList" :key="i.id" :label="i.label" :value="i.value"></el-option>
+            </template>
+            <template #area>
+              <el-cascader v-model="form.area" :props="{ value: 'name', label: 'name' }" :options="cityList" style="width: 100%" />
+            </template>
+            <template #tags>
+              <el-select v-model="form.tags" multiple filterable allow-create default-first-option :reserve-keyword="false" placeholder="请选择标签" style="width: 100%">
+                <el-option v-for="item in tagsList" :key="item.id" :label="item.title" :value="item.title" />
+              </el-select>
+            </template>
+          </custom-form>
+        </el-col>
+      </el-row>
+    </el-dialog>
+  </div>
+</template>
+
+<script setup>
+import { Search } from '@element-plus/icons-vue'
+import { cloneDeep, get } from 'lodash-es'
+const $checkRes = inject('$checkRes')
+import { UserStore } from '@/store/user'
+const userStore = UserStore()
+const user = computed(() => userStore.user)
+// 接口
+import { DemandStore } from '@/store/api/platform/demand'
+import { DictDataStore } from '@/store/api/system/dictData'
+import { TagsStore } from '@/store/api/system/tags'
+import { SectorStore } from '@/store/api/platform/sector'
+import { RegionStore } from '@/store/api/system/region'
+const regionStore = RegionStore()
+const store = DemandStore()
+const dictDataStore = DictDataStore()
+const tagsStore = TagsStore()
+const sectorStore = SectorStore()
+// 加载中
+const loading = ref(false)
+
+const searchForm = ref({})
+// 列表
+const list = ref([])
+let skip = 0
+let limit = inject('limit')
+const total = ref(0)
+const currentPage = ref(1)
+// 字典表
+const isUseList = ref([])
+const statusList = ref([])
+const methodList = ref([])
+const urgentList = ref([])
+const fieldList = ref([])
+const cityList = ref([])
+const demandList = ref([])
+const tagsList = ref([])
+const sectorList = ref([])
+
+const form = ref({ time: [] })
+const dialog = ref({ type: '1', show: false, title: '发布需求' })
+const formFields = ref([
+  { label: '需求名称', model: 'name' },
+  { label: '标签', model: 'tags', custom: true },
+  { label: '所属产业', model: 'industry', type: 'select' },
+  { label: '行业领域', model: 'field' },
+  { label: '需求紧急度', model: 'urgent', type: 'select' },
+  { label: '合作方式', model: 'method', type: 'select' },
+  { label: '价格(万元)', model: 'money' },
+  { label: '所属企业', model: 'company' },
+  { label: '企业简况', model: 'company_brief', type: 'textarea' },
+  { label: '联系人', model: 'contacts' },
+  { label: '联系电话', model: 'tel' },
+  { label: '年份', model: 'year', type: 'year' },
+  { label: '月份', model: 'month', type: 'month' },
+  { label: '技术需求名称', model: 'tec_name' },
+  { label: '待解决问题', model: 'question', type: 'textarea' },
+  { label: '需求地区', model: 'area', custom: true },
+  { label: '发布时间', model: 'time', type: 'daterange' },
+  { label: '是否公开', model: 'is_use', type: 'radio' },
+  { label: '简介', model: 'brief', type: 'textarea' }
+])
+const rules = reactive({ name: [{ required: true, message: '请输入需求名称', trigger: 'blur' }] })
+// 请求
+onMounted(async () => {
+  loading.value = true
+  await searchOther()
+  await search()
+  loading.value = false
+})
+const search = async (query = { skip, limit }) => {
+  skip = query.skip
+  limit = query.limit
+  const info = {
+    skip: query.skip,
+    limit: query.limit,
+    user: user.value.id,
+    ...searchForm.value
+  }
+  const res = await store.list(info)
+  if (res.errcode == '0') {
+    list.value = res.data
+    total.value = res.total
+  }
+}
+const searchOther = async () => {
+  let result
+  // 是否使用
+  result = await dictDataStore.query({ code: 'isUse', is_use: '0' })
+  if ($checkRes(result)) isUseList.value = result.data
+  // 状态
+  result = await dictDataStore.query({ code: 'examStatus', is_use: '0' })
+  if ($checkRes(result)) statusList.value = result.data
+  // 合作方式
+  result = await dictDataStore.query({ code: 'method', is_use: '0' })
+  if ($checkRes(result)) methodList.value = result.data
+  // 需求紧急度
+  result = await dictDataStore.query({ code: 'urgent', is_use: '0' })
+  if ($checkRes(result)) urgentList.value = result.data
+  // 技术领域
+  result = await dictDataStore.query({ code: 'field', is_use: '0' })
+  if ($checkRes(result)) fieldList.value = result.data
+  // 需求状态
+  result = await dictDataStore.query({ code: 'demandStatus', is_use: '0' })
+  if ($checkRes(result)) demandList.value = result.data
+  // 标签
+  result = await tagsStore.query({ is_use: '0' })
+  if ($checkRes(result)) tagsList.value = result.data
+  // 行业
+  result = await sectorStore.query({ is_use: '0' })
+  if ($checkRes(result)) sectorList.value = result.data
+  // 城市
+  result = await regionStore.area({ level: 'province', code: 22 })
+  if ($checkRes(result)) cityList.value = result.data
+}
+// 字典数据转换
+const getDict = (data, model) => {
+  if (data) {
+    let res
+    if (model == 'status') res = statusList.value.find((f) => f.value == data)
+    return get(res, 'label')
+  }
+}
+// 添加
+const toAdd = () => {
+  dialog.value = { type: '1', show: true, title: '发布需求' }
+}
+// 修改
+const toEdit = (data) => {
+  data.time = [data.start_time, data.end_time]
+  form.value = data
+  dialog.value = { type: '1', show: true, title: '修改需求' }
+}
+// 删除
+const toDelete = (data) => {
+  ElMessageBox.confirm(`您确认删除${data.name}该数据?`, '提示', { confirmButtonText: '确定', cancelButtonText: '取消', type: 'warning' })
+    .then(async () => {
+      const res = await store.del(data.id)
+      if ($checkRes(res, true)) {
+        search({ skip, limit })
+      }
+    })
+    .catch(() => {})
+}
+const toSave = async () => {
+  const data = cloneDeep(form.value)
+  const other = { status: '0', user: user.value.id }
+  if (data.time && data.time.length > 1) {
+    data.start_time = data.time[0]
+    data.end_time = data.time[1]
+  }
+  delete data.time
+  let res
+  if (get(data, 'id')) res = await store.update({ ...data, ...other })
+  else res = await store.create({ ...data, ...other })
+  if ($checkRes(res, true)) {
+    search({ skip, limit })
+    toClose()
+  }
+}
+const toDraftSave = async () => {
+  const data = cloneDeep(form.value)
+  const other = { status: '-2', user: user.value.id }
+  if (data.time && data.time.length > 1) {
+    data.start_time = data.time[0]
+    data.end_time = data.time[1]
+  }
+  delete data.time
+  let res
+  if (get(data, 'id')) res = await store.update({ ...data, ...other })
+  else res = await store.create({ ...data, ...other })
+  if ($checkRes(res, true)) {
+    search({ skip, limit })
+    toClose()
+  }
+}
+// 审核保存
+const toExam = async (row) => {
+  ElMessageBox.confirm(`您确认保存并提交审核该数据?`, '提示', { confirmButtonText: '确定', cancelButtonText: '取消', type: 'warning' })
+    .then(async () => {
+      const data = cloneDeep(row)
+      let res = await store.update({ id: data.id, status: '0', user: user.value.id })
+      if ($checkRes(res, true)) {
+        search({ skip, limit })
+        toClose()
+      }
+    })
+    .catch(() => {})
+}
+const toClose = () => {
+  form.value = { time: [] }
+  dialog.value = { show: false }
+}
+// 分页
+const changePage = (page = currentPage.value) => {
+  search({ skip: (page - 1) * limit, limit: limit })
+}
+const sizeChange = (limits) => {
+  limit = limits
+  currentPage.value = 1
+  search({ skip: 0, limit: limit })
+}
+</script>
+<style scoped lang="scss">
+.main {
+  .one {
+    height: 50px;
+    display: flex;
+    justify-content: space-between;
+    align-items: center;
+    margin: 0 0 10px 0;
+    .one_left {
+      background: #1875df;
+      padding: 0 10px;
+      height: 30px;
+      color: #fff;
+      line-height: 30px;
+      text-align: center;
+      font-size: 16px;
+      cursor: default;
+    }
+  }
+  .thr {
+    display: flex;
+    justify-content: center;
+    margin: 20px 0 0 0;
+  }
+}
+</style>

+ 94 - 0
src/views/center/match.vue

@@ -0,0 +1,94 @@
+<template>
+  <div class="index">
+    <el-row>
+      <el-col :span="24" class="main animate__animated animate__backInRight" v-loading="loading">
+        <el-col :span="24" class="one">
+          <el-radio-group size="large" v-model="searchForm.type">
+            <el-radio-button label="活动报名" value="1" />
+            <el-radio-button label="大赛报名" value="2" />
+          </el-radio-group>
+        </el-col>
+        <el-col :span="24" class="two">
+          <el-table :data="list" style="width: 100%" size="large" :header-cell-style="{ backgroundColor: '#edf3ff' }">
+            <template #empty>
+              <el-empty description="暂无数据" />
+            </template>
+            <el-table-column prop="name" align="center" label="标题" />
+            <el-table-column prop="time" align="center" label="报名时间" width="180" />
+            <el-table-column prop="status" align="center" label="状态" width="180" />
+            <el-table-column align="center" label="操作" width="180">
+              <template #default="{ row }">
+                <el-link :underline="false" type="primary" size="mini" @click="toEdit(row)" style="margin-right: 10px">修改</el-link>
+                <el-link :underline="false" type="danger" size="mini" @click="toDelete(row)"> 删除 </el-link>
+              </template>
+            </el-table-column>
+          </el-table>
+        </el-col>
+        <el-col :span="24" class="thr">
+          <el-pagination background layout="prev, pager, next" :total="total" :page-size="limit" v-model:current-page="currentPage" @current-change="changePage" @size-change="sizeChange" />
+        </el-col>
+      </el-col>
+    </el-row>
+  </div>
+</template>
+
+<script setup>
+import { UserStore } from '@/store/user'
+const userStore = UserStore()
+const user = computed(() => userStore.user)
+// 加载中
+const loading = ref(false)
+// 路由
+const router = useRouter()
+// 列表
+const list = ref([])
+let skip = 0
+let limit = inject('limit')
+const total = ref(0)
+const currentPage = ref(1)
+const searchForm = ref({ type: '1' })
+// 请求
+onMounted(async () => {
+  loading.value = true
+  await searchOther()
+  await search()
+  loading.value = false
+})
+const search = async (query = { skip, limit }) => {
+  // skip = query.skip
+  // limit = query.limit
+  // const info = {
+  //   skip: query.skip,
+  //   limit: query.limit,
+  //   user: user.value.id,
+  // ...searchForm.value
+  // }
+  // const res = await store.list(info)
+  // if (res.errcode == '0') {
+  //   list.value = res.data
+  //   total.value = res.total
+  // }
+}
+const searchOther = async () => {}
+// 分页
+const changePage = (page = currentPage.value) => {
+  search({ skip: (page - 1) * limit, limit: limit })
+}
+const sizeChange = (limits) => {
+  limit = limits
+  currentPage.value = 1
+  search({ skip: 0, limit: limit })
+}
+</script>
+<style scoped lang="scss">
+.main {
+  .one {
+    margin: 0 0 10px 0;
+  }
+  .thr {
+    display: flex;
+    justify-content: center;
+    margin: 20px 0 0 0;
+  }
+}
+</style>

+ 77 - 0
src/views/center/notice.vue

@@ -0,0 +1,77 @@
+<template>
+  <div class="index">
+    <el-row>
+      <el-col :span="24" class="main animate__animated animate__backInRight" v-loading="loading">
+        <el-col :span="24" class="one">
+          <el-table :data="list" style="width: 100%" size="large" :header-cell-style="{ backgroundColor: '#edf3ff' }">
+            <template #empty>
+              <el-empty description="暂无数据" />
+            </template>
+            <el-table-column prop="type" align="center" label="通知种类" width="180" />
+            <el-table-column prop="title" align="center" label="标题" />
+            <el-table-column prop="time" align="center" label="时间" width="180" />
+          </el-table>
+        </el-col>
+        <el-col :span="24" class="two">
+          <el-pagination background layout="prev, pager, next" :total="total" :page-size="limit" v-model:current-page="currentPage" @current-change="changePage" @size-change="sizeChange" />
+        </el-col>
+      </el-col>
+    </el-row>
+  </div>
+</template>
+
+<script setup>
+import { UserStore } from '@/store/user'
+const userStore = UserStore()
+const user = computed(() => userStore.user)
+// 加载中
+const loading = ref(false)
+// 路由
+const router = useRouter()
+// 列表
+const list = ref([])
+let skip = 0
+let limit = inject('limit')
+const total = ref(0)
+const currentPage = ref(1)
+// 请求
+onMounted(async () => {
+  loading.value = true
+  await searchOther()
+  await search()
+  loading.value = false
+})
+const search = async (query = { skip, limit }) => {
+  // skip = query.skip
+  // limit = query.limit
+  // const info = {
+  //   skip: query.skip,
+  //   limit: query.limit,
+  //   user: user.value.id
+  // }
+  // const res = await store.list(info)
+  // if (res.errcode == '0') {
+  //   list.value = res.data
+  //   total.value = res.total
+  // }
+}
+const searchOther = async () => {}
+// 分页
+const changePage = (page = currentPage.value) => {
+  search({ skip: (page - 1) * limit, limit: limit })
+}
+const sizeChange = (limits) => {
+  limit = limits
+  currentPage.value = 1
+  search({ skip: 0, limit: limit })
+}
+</script>
+<style scoped lang="scss">
+.main {
+  .two {
+    display: flex;
+    justify-content: center;
+    margin: 20px 0 0 0;
+  }
+}
+</style>

+ 2 - 2
src/views/center/parts/association.vue

@@ -52,7 +52,7 @@ import { UserStore } from '@/store/user'
 const userStore = UserStore()
 const user = computed(() => userStore.user)
 // 表单
-const ruleFormRef = inject('ruleFormRef')
+const ruleFormRef = ref()
 // 字典表
 const isUseList = inject('isUseList')
 // 接口
@@ -92,7 +92,7 @@ onMounted(async () => {
 const search = async () => {
   if (user.value.id) {
     let res = await associationStore.query({ user: user.value.id })
-    if (res.errcode == '0') form.value = res.data[0]
+    if (res.errcode == '0') form.value = res.data[0] || {}
   }
 }
 </script>

+ 1 - 1
src/views/center/parts/company.vue

@@ -118,7 +118,7 @@ import { UserStore } from '@/store/user'
 const userStore = UserStore()
 const user = computed(() => userStore.user)
 // 表单
-const ruleFormRef = inject('ruleFormRef')
+const ruleFormRef = ref()
 // 字典表
 const patternList = inject('patternList')
 const scaleList = inject('scaleList')

+ 2 - 2
src/views/center/parts/competition.vue

@@ -52,7 +52,7 @@ import { UserStore } from '@/store/user'
 const userStore = UserStore()
 const user = computed(() => userStore.user)
 // 表单
-const ruleFormRef = inject('ruleFormRef')
+const ruleFormRef = ref()
 // 字典表
 const isUseList = inject('isUseList')
 // 接口
@@ -92,7 +92,7 @@ onMounted(async () => {
 const search = async () => {
   if (user.value.id) {
     let res = await competitionStore.query({ user: user.value.id })
-    if (res.errcode == '0') form.value = res.data[0]
+    if (res.errcode == '0') form.value = res.data[0] || {}
   }
 }
 </script>

+ 1 - 1
src/views/center/parts/expert.vue

@@ -94,7 +94,7 @@ import { UserStore } from '@/store/user'
 const userStore = UserStore()
 const user = computed(() => userStore.user)
 // 表单
-const ruleFormRef = inject('ruleFormRef')
+const ruleFormRef = ref()
 // 字典表
 const fieldList = inject('fieldList')
 const educationList = inject('educationList')

+ 2 - 2
src/views/center/parts/incubator.vue

@@ -52,7 +52,7 @@ import { UserStore } from '@/store/user'
 const userStore = UserStore()
 const user = computed(() => userStore.user)
 // 表单
-const ruleFormRef = inject('ruleFormRef')
+const ruleFormRef = ref()
 // 字典表
 const isUseList = inject('isUseList')
 // 接口
@@ -92,7 +92,7 @@ onMounted(async () => {
 const search = async () => {
   if (user.value.id) {
     let res = await incubatorStore.query({ user: user.value.id })
-    if (res.errcode == '0') form.value = res.data[0]
+    if (res.errcode == '0') form.value = res.data[0] || {}
   }
 }
 </script>

+ 2 - 2
src/views/center/parts/investment.vue

@@ -68,7 +68,7 @@ import { UserStore } from '@/store/user'
 const userStore = UserStore()
 const user = computed(() => userStore.user)
 // 表单
-const ruleFormRef = inject('ruleFormRef')
+const ruleFormRef = ref()
 // 字典表
 const cardTypeList = inject('cardTypeList')
 const isUseList = inject('isUseList')
@@ -110,7 +110,7 @@ onMounted(async () => {
 const search = async () => {
   if (user.value.id) {
     let res = await investmentStore.query({ user: user.value.id })
-    if (res.errcode == '0') form.value = res.data[0]
+    if (res.errcode == '0') form.value = res.data[0] || {}
   }
 }
 </script>

+ 2 - 2
src/views/center/parts/state.vue

@@ -61,7 +61,7 @@ import { UserStore } from '@/store/user'
 const userStore = UserStore()
 const user = computed(() => userStore.user)
 // 表单
-const ruleFormRef = inject('ruleFormRef')
+const ruleFormRef = ref()
 // 字典表
 const isUseList = inject('isUseList')
 // 接口
@@ -101,7 +101,7 @@ onMounted(async () => {
 const search = async () => {
   if (user.value.id) {
     let res = await stateStore.query({ user: user.value.id })
-    if (res.errcode == '0') form.value = res.data[0]
+    if (res.errcode == '0') form.value = res.data[0] || {}
   }
 }
 </script>

+ 2 - 2
src/views/center/parts/unit.vue

@@ -52,7 +52,7 @@ import { UserStore } from '@/store/user'
 const userStore = UserStore()
 const user = computed(() => userStore.user)
 // 表单
-const ruleFormRef = inject('ruleFormRef')
+const ruleFormRef = ref()
 // 字典表
 const isUseList = inject('isUseList')
 // 接口
@@ -92,7 +92,7 @@ onMounted(async () => {
 const search = async () => {
   if (user.value.id) {
     let res = await unitStore.query({ user: user.value.id })
-    if (res.errcode == '0') form.value = res.data[0]
+    if (res.errcode == '0') form.value = res.data[0] || {}
   }
 }
 </script>

+ 0 - 1
src/views/detail/studyDetail.vue

@@ -84,7 +84,6 @@ const changePage = (page = currentPage.value) => {
   search({ skip: (page - 1) * limit, limit: limit })
 }
 const sizeChange = (limits) => {
-  console.log(limits)
   limit = limits
   currentPage.value = 1
   search({ skip: 0, limit: limit })

+ 7 - 0
src/views/login/parts/login.vue

@@ -129,6 +129,13 @@ const toTab = async (active) => {
 }
 // 登录
 const submitForm = async (formEl) => {
+  if (!isAgree.value) {
+    ElMessage({
+      message: '请阅读并同意用户协议和隐私政策',
+      type: 'warning'
+    })
+    return
+  }
   if (!formEl) return
   await formEl.validate(async (valid, fields) => {
     if (valid) {

+ 0 - 1
src/views/nine/index.vue

@@ -305,7 +305,6 @@ const changePage = (page = currentPage.value) => {
   search({ skip: (page - 1) * limit, limit: limit })
 }
 const sizeChange = (limits) => {
-  console.log(limits)
   limit = limits
   currentPage.value = 1
   search({ skip: 0, limit: limit })

+ 0 - 1
src/views/search/parts/achievement.vue

@@ -303,7 +303,6 @@ const changePage = (page = currentPage.value) => {
   search({ skip: (page - 1) * limit, limit: limit })
 }
 const sizeChange = (limits) => {
-  console.log(limits)
   limit = limits
   currentPage.value = 1
   search({ skip: 0, limit: limit })

+ 0 - 1
src/views/search/parts/demand.vue

@@ -175,7 +175,6 @@ const changePage = (page = currentPage.value) => {
   search({ skip: (page - 1) * limit, limit: limit })
 }
 const sizeChange = (limits) => {
-  console.log(limits)
   limit = limits
   currentPage.value = 1
   search({ skip: 0, limit: limit })

+ 0 - 1
src/views/search/parts/supply.vue

@@ -200,7 +200,6 @@ const changePage = (page = currentPage.value) => {
   search({ skip: (page - 1) * limit, limit: limit })
 }
 const sizeChange = (limits) => {
-  console.log(limits)
   limit = limits
   currentPage.value = 1
   search({ skip: 0, limit: limit })

+ 0 - 1
src/views/thr/index.vue

@@ -138,7 +138,6 @@ const changePage = (page = currentPage.value) => {
   search({ skip: (page - 1) * limit, limit: limit })
 }
 const sizeChange = (limits) => {
-  console.log(limits)
   limit = limits
   currentPage.value = 1
   search({ skip: 0, limit: limit })