Procházet zdrojové kódy

修改项目管理

zs před 1 rokem
rodič
revize
9d3a2cd818

+ 7 - 0
src/App.vue

@@ -18,4 +18,11 @@ body {
   width: 1200px;
   margin: 0 auto;
 }
+.textOver {
+  display: -webkit-box;
+  -webkit-line-clamp: 2;
+  -webkit-box-orient: vertical;
+  overflow: hidden;
+  text-overflow: ellipsis;
+}
 </style>

binární
src/assets/science_1.png


binární
src/assets/science_2.png


binární
src/assets/science_3.png


binární
src/assets/science_4.png


binární
src/assets/science_5.png


binární
src/assets/science_6.png


binární
src/assets/science_7.png


binární
src/assets/science_8.png


binární
src/assets/science_9.png


+ 27 - 9
src/layout/index.vue

@@ -2,7 +2,7 @@
   <div class="common-layout">
     <div class="top">
       <el-row :gutter="20" align="middle">
-        <el-col :span="9" class="top_1">
+        <el-col :span="8" class="top_1">
           <el-image class="image" :src="siteInfo.logoUrl" fit="fill" />
           <div class="content">
             <text class="title">{{ siteInfo.zhTitle }}</text>
@@ -14,11 +14,29 @@
             <a-tab-pane v-for="item in menuList" :key="item.href" :tab="item.title"> </a-tab-pane>
           </a-tabs>
         </el-col>
-        <el-col :span="3">
+        <el-col :span="4">
           <el-row :gutter="20">
-            <el-col :span="12" v-if="user && user._id" class="top_3">
+            <el-col :span="6" class="top_2">
+              <el-button :icon="Search" size="small">搜索</el-button>
+            </el-col>
+            <el-col :span="6" class="top_2">
+              <el-dropdown>
+                <el-button size="small" :icon="Edit">发布</el-button>
+                <template #dropdown>
+                  <el-dropdown-menu>
+                    <el-dropdown-item>发布需求</el-dropdown-item>
+                    <el-dropdown-item>发布成果</el-dropdown-item>
+                    <el-dropdown-item>发布项目</el-dropdown-item>
+                  </el-dropdown-menu>
+                </template>
+              </el-dropdown>
+            </el-col>
+            <el-col :span="6" class="top_2" v-if="user && user._id">
+              <el-button :icon="Bell" size="small">消息</el-button>
+            </el-col>
+            <el-col :span="6" v-if="user && user._id" class="top_3">
               <el-dropdown>
-                <el-button type="primary">
+                <el-button size="small" :icon="User" type="primary">
                   {{ user.nick_name || '游客' }}
                 </el-button>
                 <template #dropdown>
@@ -30,10 +48,9 @@
                 </template>
               </el-dropdown>
             </el-col>
-            <el-col :span="12" v-else class="top_3">
-              <text @click="toLogin(1)">登录</text>
-              <text>|</text>
-              <text @click="toLogin(2)">注册</text>
+            <el-col :span="10" v-else class="top_3">
+              <el-button @click="toLogin(1)" type="primary" size="small">登录</el-button>
+              <el-button @click="toLogin(2)" type="primary" size="small">注册</el-button>
             </el-col>
           </el-row>
         </el-col>
@@ -79,6 +96,7 @@
 
 <script setup>
 import { siteInfo, footInfo, menuList } from '@/layout/site'
+import { Search, Edit, User, Bell } from '@element-plus/icons-vue'
 const router = useRouter()
 const route = useRoute()
 const current = ref(route.name || 'home')
@@ -108,7 +126,7 @@ const toOpen = async () => {
 }
 // 个人中心
 const toCenter = () => {
-  console.log('个人中心')
+  router.push('/center')
 }
 // 退出登录
 const toLogout = () => {

+ 1 - 0
src/layout/site.js

@@ -27,6 +27,7 @@ export const menuList = [
   { title: '政策新闻', href: 'news', English: 'Policy News' },
   { title: '新闻资讯', href: 'brain', English: 'News Information' },
   { title: '供需商城', href: 'demand', English: 'Demand Mall' },
+  { title: '科技赛道', href: 'science', English: 'Science Technology' },
   { title: '创新大赛', href: 'innovation', English: 'Innovation Competition' },
   { title: '成果展示', href: 'achievement', English: 'Achievement Display' }
 ]

+ 11 - 0
src/router/index.js

@@ -44,6 +44,12 @@ const router = createRouter({
           meta: { title: '吉林省信息技术孵化平台-新闻资讯' },
           component: () => import('@/views/brain/index.vue')
         },
+        {
+          path: '/science',
+          name: 'science',
+          meta: { title: '吉林省信息技术孵化平台-科技赛道' },
+          component: () => import('@/views/science/index.vue')
+        },
         {
           path: '/innovation',
           name: 'innovation',
@@ -86,6 +92,11 @@ const router = createRouter({
           meta: { title: '吉林省信息技术孵化平台-用户注册' },
           component: () => import('@/views/register/index.vue')
         },
+        {
+          path: '/center',
+          meta: { title: '吉林省信息技术孵化平台-个人中心' },
+          component: () => import('@/views/center/index.vue')
+        },
         {
           path: '/help',
           meta: { title: '吉林省信息技术孵化平台-帮助中心' },

+ 40 - 0
src/store/api/platform/project.js

@@ -0,0 +1,40 @@
+import { defineStore } from 'pinia'
+import { AxiosWrapper } from '@/utils/axios-wrapper'
+import { get } from 'lodash-es'
+const url = '/project'
+const axios = new AxiosWrapper()
+
+export const ProjectStore = defineStore('project', () => {
+  const query = async ({ skip = 0, limit = undefined, ...info } = {}) => {
+    let cond = {}
+    if (skip) cond.skip = skip
+    if (limit) cond.limit = limit
+    cond = { ...cond, ...info }
+    const res = await axios.$get(`${url}`, cond)
+    return res
+  }
+  const fetch = async (payload) => {
+    const res = await axios.$get(`${url}/${payload}`)
+    return res
+  }
+  const create = async (payload) => {
+    const res = await axios.$post(`${url}`, payload)
+    return res
+  }
+  const update = async (payload) => {
+    const id = get(payload, 'id', get(payload, '_id'))
+    const res = await axios.$post(`${url}/${id}`, payload)
+    return res
+  }
+  const del = async (payload) => {
+    const res = await axios.$delete(`${url}/${payload}`)
+    return res
+  }
+  return {
+    query,
+    fetch,
+    create,
+    update,
+    del
+  }
+})

+ 40 - 0
src/store/api/user/user.js

@@ -0,0 +1,40 @@
+import { defineStore } from 'pinia'
+import { AxiosWrapper } from '@/utils/axios-wrapper'
+import { get } from 'lodash-es'
+const url = '/user'
+const axios = new AxiosWrapper()
+
+export const UserStore = defineStore('users', () => {
+  const query = async ({ skip = 0, limit = undefined, ...info } = {}) => {
+    let cond = {}
+    if (skip) cond.skip = skip
+    if (limit) cond.limit = limit
+    cond = { ...cond, ...info }
+    const res = await axios.$get(`${url}`, cond)
+    return res
+  }
+  const fetch = async (payload) => {
+    const res = await axios.$get(`${url}/${payload}`)
+    return res
+  }
+  const create = async (payload) => {
+    const res = await axios.$post(`${url}`, payload)
+    return res
+  }
+  const update = async (payload) => {
+    const id = get(payload, 'id', get(payload, '_id'))
+    const res = await axios.$post(`${url}/${id}`, payload)
+    return res
+  }
+  const del = async (payload) => {
+    const res = await axios.$delete(`${url}/${payload}`)
+    return res
+  }
+  return {
+    query,
+    fetch,
+    create,
+    update,
+    del
+  }
+})

+ 98 - 0
src/views/center/index.vue

@@ -0,0 +1,98 @@
+<template>
+  <div id="index">
+    <el-row>
+      <el-col :span="24" class="main animate__animated animate__backInRight" v-loading="loading">
+        <div class="w_1200">
+          <el-form
+            ref="ruleFormRef"
+            :model="form"
+            :rules="rules"
+            label-width="80px"
+            class="form"
+            label-position="left"
+          >
+            <el-form-item label="账号" prop="account">
+              <el-input v-model="form.account" placeholder="请输入账号">
+                <template #prefix>
+                  <el-icon>
+                    <User />
+                  </el-icon>
+                </template>
+              </el-input>
+            </el-form-item>
+            <el-form-item label="昵称" prop="nick_name">
+              <el-input 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 v-model="form.gender" 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 v-model="form.phone" placeholder="请输入手机号">
+                <template #prefix>
+                  <el-icon>
+                    <Iphone />
+                  </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>
+        </div>
+      </el-col>
+    </el-row>
+  </div>
+</template>
+
+<script setup>
+import { useRoute } from 'vue-router'
+const route = useRoute()
+// 加载中
+const loading = ref(false)
+const form = ref({ role: ['user'] })
+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' }],
+  account: [{ required: true, message: '请输入账号', trigger: 'blur' }]
+})
+// 请求
+onMounted(async () => {
+  loading.value = true
+  search()
+  loading.value = false
+})
+const search = async () => {}
+</script>
+<style scoped lang="scss">
+.main {
+  padding: 20px;
+  .button {
+    text-align: center;
+  }
+}
+</style>

+ 0 - 3
src/views/help/index.vue

@@ -57,9 +57,6 @@
 </template>
 
 <script setup>
-// 基础
-import { onMounted, ref, reactive } from 'vue'
-import { useRoute } from 'vue-router'
 // 图片引入
 import map from '@/assets/map.jpg'
 const route = useRoute()

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

@@ -27,7 +27,7 @@
                   </el-col>
                   <el-col :span="4" v-if="user && user._id" class="right_3">
                     <el-dropdown>
-                      <el-button type="primary">
+                      <el-button type="primary" size="mini">
                         {{ user.nick_name || '游客' }}
                       </el-button>
                       <template #dropdown>
@@ -39,9 +39,8 @@
                     </el-dropdown>
                   </el-col>
                   <el-col :span="4" v-else class="right_3">
-                    <text @click="toCommon(1)">登录</text>
-                    <text>|</text>
-                    <text @click="toCommon(2)">注册</text>
+                    <el-button @click="toLogin(1)" type="primary" size="small">登录</el-button>
+                    <el-button @click="toLogin(2)" type="primary" size="small">注册</el-button>
                   </el-col>
                 </el-row>
               </el-col>

+ 285 - 0
src/views/science/index.vue

@@ -0,0 +1,285 @@
+<template>
+  <div id="index">
+    <el-row>
+      <el-col :span="24" class="main animate__animated animate__backInRight" v-loading="loading">
+        <el-col :span="24" class="science">
+          <el-image class="image" :src="science" fit="fill" />
+        </el-col>
+        <div class="w_1200">
+          <el-col :span="24" class="one">
+            <el-col :span="24" class="one_1">
+              <el-col :span="12" class="left">汇聚科技创新的创新赛道</el-col>
+              <el-col :span="12" class="right">查看全部项目</el-col>
+            </el-col>
+            <el-col :span="24" class="one_2">
+              <el-col :span="4" class="left">
+                <el-col
+                  :span="24"
+                  class="list"
+                  v-for="(item, index) in typeList"
+                  :key="index"
+                  @onmouseover="mouseOver(item)"
+                >
+                  <el-col :span="6" class="image">
+                    <el-image class="image" :src="item.url" fit="fill" />
+                  </el-col>
+                  <el-col :span="18" class="title">{{ item.title }}</el-col>
+                </el-col>
+              </el-col>
+              <el-col :span="20" class="right">
+                <el-col
+                  :span="7"
+                  class="list"
+                  v-for="(item, index) in list"
+                  :key="index"
+                  @click="toView(item)"
+                >
+                  <el-col :span="24" class="name">{{ item.name || '暂无项目名称' }}</el-col>
+                  <el-col :span="24" class="brief textOver">
+                    项目介绍:{{ item.brief || '暂无项目介绍' }}
+                  </el-col>
+                  <el-col :span="24" class="info">
+                    <div>技术成熟度:{{ getDict(item.maturity, 'maturity') }}</div>
+                    <div>合作类型:{{ getDict(item.cooperate, 'cooperate') }}</div>
+                  </el-col>
+                  <span class="key">{{ getDict(item.type, 'type') }}</span>
+                </el-col>
+              </el-col>
+            </el-col>
+          </el-col>
+          <el-col :span="24" class="one">
+            <el-col :span="24" class="one_1">
+              <el-col :span="12" class="left">汇聚各种行业的专家通</el-col>
+              <el-col :span="12" class="right">查看更多专家</el-col>
+            </el-col>
+            <el-col :span="24" class="one_2"> </el-col>
+          </el-col>
+        </div>
+      </el-col>
+    </el-row>
+  </div>
+</template>
+
+<script setup>
+const $checkRes = inject('$checkRes')
+import { get } from 'lodash-es'
+// 接口
+import { DictDataStore } from '@/store/api/system/dictData'
+import { ProjectStore } from '@/store/api/platform/project'
+const store = ProjectStore()
+const dictDataStore = DictDataStore()
+// 路由
+const route = useRoute()
+// 图片引入
+import science from '@/assets/news.png'
+import science_1 from '@/assets/science_1.png'
+import science_2 from '@/assets/science_2.png'
+import science_3 from '@/assets/science_3.png'
+import science_4 from '@/assets/science_4.png'
+import science_5 from '@/assets/science_5.png'
+import science_6 from '@/assets/science_6.png'
+import science_7 from '@/assets/science_7.png'
+import science_8 from '@/assets/science_8.png'
+import science_9 from '@/assets/science_9.png'
+// 加载中
+const loading = ref(false)
+const typeList = ref([
+  { url: science_1, title: '生物技术', type: '0' },
+  { url: science_2, title: '信息技术', type: '1' },
+  { url: science_3, title: '新材料', type: '2' },
+  { url: science_4, title: '新能源', type: '3' },
+  { url: science_5, title: '智能制造', type: '4' },
+  { url: science_6, title: '光电芯片', type: '5' },
+  { url: science_7, title: '人工智能', type: '6' },
+  { url: science_8, title: '航空航天', type: '7' },
+  { url: science_9, title: '其他', type: '8' }
+])
+const list = ref([])
+const projectList = ref([])
+const maturityList = ref([])
+const industryList = ref([])
+// 请求
+onMounted(async () => {
+  loading.value = true
+  await searchOther()
+  await search()
+  loading.value = false
+})
+const searchOther = async () => {
+  let result
+  // 合作类型
+  result = await dictDataStore.query({ code: 'projectType', is_use: '0' })
+  if ($checkRes(result)) projectList.value = result.data
+  // 成熟度
+  result = await dictDataStore.query({ code: 'projectMaturity', is_use: '0' })
+  if ($checkRes(result)) maturityList.value = result.data
+  // 行业分类
+  result = await dictDataStore.query({ code: 'industry', is_use: '0' })
+  if ($checkRes(result)) industryList.value = result.data
+}
+const search = async (data) => {
+  const info = {
+    skip: 0,
+    limit: 9,
+    is_use: '0',
+    status: '1'
+  }
+  if (data?.type) info.type = data.type
+  const res = await store.query(info)
+  if (res.errcode == '0') list.value = res.data
+}
+// 字典数据转换
+const getDict = (data, model) => {
+  let res
+  if (model == 'cooperate') res = projectList.value.find((f) => f.value == data)
+  else if (model == 'maturity') res = maturityList.value.find((f) => f.value == data)
+  else if (model == 'type') res = industryList.value.find((f) => f.value == data)
+  return get(res, 'label')
+}
+// 查看详情
+const toView = (item) => {
+  console.log(item)
+}
+// 查询
+const mouseOver = (item) => {
+  console.log(item)
+}
+</script>
+<style scoped lang="scss">
+.main {
+  .science {
+    .image {
+      width: 100%;
+      height: 250px;
+    }
+  }
+  .one {
+    padding: 25px 0;
+    .one_1 {
+      display: flex;
+      justify-content: space-between;
+      margin: 0 0 10px 0;
+      .left {
+        font-size: 24px;
+        font-family:
+          PingFangSC-Semibold,
+          PingFang SC;
+        font-weight: 600;
+        color: #111;
+        line-height: 33px;
+      }
+      .right {
+        text-align: right;
+        font-size: 14px;
+        font-family:
+          PingFangSC-Regular,
+          PingFang SC;
+        font-weight: 400;
+        color: #2280ff;
+        line-height: 14px;
+        display: block;
+        margin-top: 13px;
+        margin-right: 34px;
+      }
+    }
+    .one_2 {
+      display: flex;
+      .left {
+        padding: 10px;
+        .list {
+          display: flex;
+          padding: 15px;
+          border-radius: 8px;
+          .image {
+            text-align: center;
+            width: 20px;
+            height: 20px;
+          }
+          .title {
+            font-size: 16px;
+            font-family:
+              PingFangSC-Regular,
+              PingFang SC;
+            font-weight: 400;
+            color: #111;
+            line-height: 22px;
+          }
+        }
+        .list:hover {
+          border-radius: 8px;
+          background-color: #2280ff;
+          .title {
+            color: #ffffff;
+          }
+        }
+      }
+      .right {
+        display: flex;
+        justify-content: space-around;
+        align-items: flex-start;
+        flex-wrap: wrap;
+        .list {
+          padding: 20px;
+          border-radius: 10px;
+          margin: 0 0 10px 0;
+
+          .name {
+            font-size: 16px;
+            font-family:
+              PingFangSC-Medium,
+              PingFang SC;
+            font-weight: 500;
+            color: #111;
+            line-height: 16px;
+            display: block;
+            width: 100%;
+            margin: 12px 0;
+          }
+          .brief {
+            font-size: 14px;
+            font-family:
+              PingFangSC-Regular,
+              PingFang SC;
+            font-weight: 400;
+            color: #333;
+            line-height: 24px;
+            margin-bottom: 12px;
+          }
+          .info {
+            display: flex;
+            justify-content: space-between;
+            font-size: 12px;
+            font-family:
+              PingFangSC-Regular,
+              PingFang SC;
+            font-weight: 400;
+            color: #666;
+            line-height: 12px;
+            margin-bottom: 15px;
+          }
+          .key {
+            font-size: 12px;
+            font-family:
+              PingFangSC-Regular,
+              PingFang SC;
+            font-weight: 400;
+            color: #999990;
+            line-height: 20px;
+            height: 22px;
+            border-radius: 2px;
+            border: 1px solid #dbdbdb;
+            box-sizing: border-box;
+            padding: 0 6px;
+          }
+        }
+        .list:nth-child(1n) {
+          background: linear-gradient(180deg, #d5e5ff, #fff);
+        }
+        .list:nth-child(2n) {
+          background: linear-gradient(180deg, #cbeff8, #fff);
+        }
+      }
+    }
+  }
+}
+</style>