Browse Source

修改个人中心

zs 8 tháng trước cách đây
mục cha
commit
640329c9a2

+ 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">

+ 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>

+ 10 - 1
src/layout/index.vue

@@ -76,6 +76,15 @@ const toOut = () => {
 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 {
@@ -108,7 +117,7 @@ const getUrl = (item) => {
     }
     .left_2 {
       padding-left: 15px;
-      padding-top: 25px;
+      padding-top: 35px;
       .menus {
         font-size: $global-font-size-20;
         font-weight: 500;

+ 7 - 7
src/layout/site.js

@@ -140,11 +140,11 @@ export const menuList2 = [
 ]
 // 目录设置
 export const menuList3 = [
-  { id: 1, name: '基本信息', route_name: 'center', path: '/center', icon: 'House' },
-  { id: 2, name: '认证入驻', route_name: 'attestation', path: '/attestation', icon: 'House' },
-  { id: 3, name: '通知管理', route_name: 'notice', path: '/notice', icon: 'House' },
-  { id: 4, name: '成果管理', route_name: 'achievement', path: '/achievement', icon: 'House' },
-  { id: 5, name: '需求管理', route_name: 'demand', path: '/demand', icon: 'House' },
-  { id: 6, name: '我的收藏', route_name: 'collect', path: '/collect', icon: 'House' },
-  { id: 7, name: '活动管理', route_name: 'match', path: '/match', icon: 'House' }
+  { 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' }
 ]

+ 290 - 3
src/views/center/achievement.vue

@@ -2,22 +2,309 @@
   <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="one">
+          <div class="one_left" @click="toAdd">发布成果</div>
+          <div class="one_right">
+            <el-input v-model="searchForm.name" style="width: 250px" size="large" placeholder="搜索" :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 router = useRouter()
+
+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>

+ 132 - 2
src/views/center/attestation.vue

@@ -3,21 +3,151 @@
     <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 router = useRouter()
+// 字典
+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') 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>

+ 131 - 2
src/views/center/basic.vue

@@ -3,21 +3,150 @@
     <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 router = useRouter()
+// 字典
+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') 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)
+      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>

+ 125 - 3
src/views/center/collect.vue

@@ -2,22 +2,144 @@
   <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="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="搜索" :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 router = useRouter()
+// 列表
+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>

+ 280 - 3
src/views/center/demand.vue

@@ -2,22 +2,299 @@
   <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="one">
+          <div class="one_left" @click="toAdd">发布需求</div>
+          <div class="one_right">
+            <el-input v-model="searchForm.name" style="width: 250px" size="large" placeholder="搜索" :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 router = useRouter()
+
+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>

+ 72 - 1
src/views/center/match.vue

@@ -2,7 +2,31 @@
   <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="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>
@@ -16,8 +40,55 @@ 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>

+ 55 - 1
src/views/center/notice.vue

@@ -2,7 +2,19 @@
   <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="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>
@@ -16,8 +28,50 @@ 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 })

+ 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 })