Selaa lähdekoodia

修改联系方式

zs 8 kuukautta sitten
vanhempi
commit
fc8a0f10e6

+ 331 - 0
src/views/center/company.vue

@@ -0,0 +1,331 @@
+<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">
+            <div class="button" @click="toAdd">发布成果</div>
+            <div class="button" @click="toTemplate">下载导出模板</div>
+            <div class="button" @click="toUExcel">上传Excel</div>
+            <div class="button" @click="toDownload">下载Excel</div>
+          </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.query(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 toTemplate = () => {
+  console.log('下载导出模板')
+}
+// 上传Excel
+const toUExcel = () => {
+  console.log('上传Excel')
+}
+// 下载Excel
+const toDownload = () => {
+  console.log('下载Excel')
+}
+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 {
+      display: flex;
+      font-size: 16px;
+      .button {
+        background: #1875df;
+        padding: 0 10px;
+        height: 30px;
+        color: #fff;
+        line-height: 30px;
+        text-align: center;
+        cursor: default;
+        margin: 0 10px 0 0;
+      }
+    }
+  }
+  .thr {
+    display: flex;
+    justify-content: center;
+    margin: 20px 0 0 0;
+  }
+}
+</style>

+ 25 - 2
src/views/detail/achievementDetail.vue

@@ -35,10 +35,10 @@
               <el-image class="image" :src="icon9" fit="fill" />
               <span class="span">负责人:{{ info.person || '暂无' }}</span>
             </div>
-            <div class="value" v-if="user && user.id">
+            <!-- <div class="value" v-if="user && user.id">
               <el-image class="image" :src="icon6" fit="fill" />
               <span class="span">联系电话:{{ info.tel || '暂无' }}</span>
-            </div>
+            </div> -->
             <div class="value">
               <el-image class="image" :src="icon7" fit="fill" />
               <span class="span">专利情况:{{ info.patent || '暂无' }}</span>
@@ -47,6 +47,9 @@
               <el-image class="image" :src="icon8" fit="fill" />
               <span class="span">技术标签:{{ info.label || '暂无' }}</span>
             </div>
+            <div class="infoButton">
+              <div class="button" @click="toChat">获取联系方式</div>
+            </div>
           </div>
         </div>
         <div class="info_2">
@@ -189,6 +192,11 @@ const toCollect = async () => {
     }
   } else ElMessage({ message: '未登录!', type: 'error' })
 }
+const toChat = () => {
+  if (user.value.id) {
+    console.log('获取联系方式')
+  } else ElMessage({ message: '未登录!', type: 'error' })
+}
 </script>
 <style scoped lang="scss">
 .main {
@@ -246,6 +254,21 @@ const toCollect = async () => {
             color: #18284d;
           }
         }
+        .infoButton {
+          margin: 10px 0 0 0;
+          .button {
+            width: 152px;
+            height: 36px;
+            background: #3278f4;
+            border-radius: 18px;
+            font-size: $global-font-size-14;
+            font-weight: 500;
+            color: #ffffff;
+            text-align: center;
+            line-height: 36px;
+            cursor: pointer;
+          }
+        }
       }
     }
     .info_2 {

+ 1 - 1
src/views/detail/baseDetail.vue

@@ -62,7 +62,7 @@
                     <el-col :span="24" class="other">
                       <el-col :span="24" class="other_1">
                         <span>负责人姓名:</span>
-                        {{ item.field || '暂无' }}
+                        {{ item.person || '暂无' }}
                       </el-col>
                       <el-col :span="24" class="other_1">
                         <span>所在地区:</span>

+ 26 - 2
src/views/detail/demandDetail.vue

@@ -40,13 +40,17 @@
               <p v-if="user && user.id">
                 联 系 人 :<span>{{ info.contacts || '暂无' }}</span>
               </p>
-              <p v-if="user && user.id">
+              <!-- <p v-if="user && user.id">
                 联系电话:<span>{{ info.tel || '暂无' }}</span>
-              </p>
+              </p> -->
             </div>
           </div>
           <div class="state">待解决</div>
         </div>
+        <div class="title"><i></i>联系方式</div>
+        <div class="infoButton">
+          <div class="button" @click="toChat">获取联系方式</div>
+        </div>
         <div class="title"><i></i>需求描述</div>
         <div class="info_3">
           <p>{{ info.brief || '暂无' }}</p>
@@ -213,6 +217,11 @@ const toCollect = async () => {
     }
   } else ElMessage({ message: '未登录!', type: 'error' })
 }
+const toChat = () => {
+  if (user.value.id) {
+    console.log('获取联系方式')
+  } else ElMessage({ message: '未登录!', type: 'error' })
+}
 </script>
 <style scoped lang="scss">
 .main {
@@ -310,6 +319,21 @@ const toCollect = async () => {
         font-size: $global-font-size-16;
       }
     }
+    .infoButton {
+      margin: 10px 0 0 0;
+      .button {
+        width: 152px;
+        height: 36px;
+        background: #3278f4;
+        border-radius: 18px;
+        font-size: $global-font-size-14;
+        font-weight: 500;
+        color: #ffffff;
+        text-align: center;
+        line-height: 36px;
+        cursor: pointer;
+      }
+    }
     .title {
       margin-top: 30px;
       font-size: $global-font-size-20;

+ 26 - 0
src/views/detail/expertDetail.vue

@@ -24,6 +24,9 @@
               </div>
             </div>
           </div>
+          <div class="infoButton">
+            <div class="button" @click="toChat">获取联系方式</div>
+          </div>
           <div class="infoBrief">
             <div class="Brief_1">
               <span>所属产业:</span>
@@ -138,6 +141,11 @@ const searchOther = async () => {
 const toActive = (item) => {
   active.value = item
 }
+const toChat = () => {
+  if (user.value.id) {
+    console.log('获取联系方式')
+  } else ElMessage({ message: '未登录!', type: 'error' })
+}
 const toCollect = async () => {
   if (user.value.id) {
     info.value.is_collection = !info.value.is_collection
@@ -219,6 +227,24 @@ const toCollect = async () => {
           }
         }
       }
+      .infoButton {
+        display: flex;
+        justify-content: center;
+        margin: 10px 0 0 0;
+        .button {
+          width: 152px;
+          height: 36px;
+          background: #3278f4;
+          border-radius: 18px;
+          font-size: $global-font-size-14;
+          font-weight: 500;
+          color: #ffffff;
+          text-align: center;
+          line-height: 36px;
+          cursor: pointer;
+        }
+      }
+
       .infoBrief {
         background: rgba(194, 209, 225, 0.5);
         padding: 20px;

+ 25 - 0
src/views/detail/supplyDetail.vue

@@ -41,6 +41,10 @@
           </div>
           <!-- <div class="state">待解决</div> -->
         </div>
+        <div class="title"><i></i>联系方式</div>
+        <div class="infoButton">
+          <div class="button" @click="toChat">获取联系方式</div>
+        </div>
         <div class="title"><i></i>供给描述</div>
         <div class="info_3">
           <p>{{ info.brief || '暂无' }}</p>
@@ -202,6 +206,11 @@ const toCollect = async () => {
     }
   } else ElMessage({ message: '未登录!', type: 'error' })
 }
+const toChat = () => {
+  if (user.value.id) {
+    console.log('获取联系方式')
+  } else ElMessage({ message: '未登录!', type: 'error' })
+}
 </script>
 <style scoped lang="scss">
 .main {
@@ -276,6 +285,7 @@ const toCollect = async () => {
           }
         }
       }
+
       .state {
         background: url(/images/icon-hzxq-state2.png);
         position: absolute;
@@ -288,6 +298,21 @@ const toCollect = async () => {
         font-size: $global-font-size-16;
       }
     }
+    .infoButton {
+      margin: 10px 0 0 0;
+      .button {
+        width: 152px;
+        height: 36px;
+        background: #3278f4;
+        border-radius: 18px;
+        font-size: $global-font-size-14;
+        font-weight: 500;
+        color: #ffffff;
+        text-align: center;
+        line-height: 36px;
+        cursor: pointer;
+      }
+    }
     .title {
       margin-top: 30px;
       font-size: $global-font-size-20;

+ 125 - 0
src/views/thirteen/index copy.vue

@@ -0,0 +1,125 @@
+<template>
+  <custom-layout class="main">
+    <el-col :span="24" class="one">
+      <el-image class="image" :src="news" fit="fill" />
+    </el-col>
+    <el-col :span="24" class="two">
+      <div class="w_1300 flex">
+        <el-col :span="11" class="two_1" v-for="(item, index) in list" :key="index" @click="toView(item)">
+          <div class="top">
+            <el-image class="image" :src="getUrl(item.file)" fit="fill" />
+            <div class="text">
+              <h5 class="title" style="padding-top: 0px">{{ item.name || '暂无标题' }}</h5>
+            </div>
+          </div>
+          <div class="bottom textMore">{{ item.brief || '暂无' }}</div>
+        </el-col>
+      </div>
+    </el-col>
+  </custom-layout>
+</template>
+
+<script setup>
+// 图片引入
+import news from '/images/news.png'
+// 接口
+import { JournalStore } from '@/store/api/platform/journal'
+import { DictDataStore } from '@/store/api/system/dictData'
+const store = JournalStore()
+const dictDataStore = DictDataStore()
+// 路由
+const router = useRouter()
+// 加载中
+const loading = ref(false)
+const list = ref([])
+let skip = 0
+let limit = 8
+const total = ref(0)
+// 请求
+onMounted(async () => {
+  loading.value = true
+  await search({ skip, limit })
+  loading.value = false
+})
+const search = async (query = { skip, limit }) => {
+  skip = query.skip
+  limit = query.limit
+  const info = { skip: query.skip, limit: query.limit, status: '1', is_use: '0' }
+  const res = await store.query(info)
+  if (res.errcode == '0') {
+    list.value = res.data
+    total.value = res.total
+  }
+}
+// 查看详情
+const toView = async (item) => {
+  router.push({ path: '/thirteen/list', query: { id: item.id || item._id } })
+}
+const getUrl = (item) => {
+  if (item && item.length > 0) return `${import.meta.env.VITE_APP_HOST}${item[0].uri}`
+}
+</script>
+<style scoped lang="scss">
+.main {
+  .one {
+    .image {
+      width: 100%;
+      height: 200px;
+    }
+  }
+
+  .two {
+    margin: 10px 0;
+    .flex {
+      display: flex;
+      justify-content: space-around;
+    }
+    .two_1 {
+      .top {
+        position: relative;
+        .image {
+          width: 100%;
+          height: 400px;
+        }
+        .text {
+          position: absolute;
+          left: 0;
+          bottom: 5px;
+          width: 100%;
+          padding: 0 8px;
+          background-color: rgba(0, 0, 0, 0.6);
+          background-image: none;
+          background-repeat: repeat;
+          background-position: 0 0;
+          background: -moz-linear-gradient(top, none, none);
+          background: -o-linear-gradient(top, none, none);
+          background: linear-gradient(top, none, none);
+          background: -webkit-gradient(linear, left top, left bottom, from(none), to(none));
+          box-sizing: border-box;
+          .title {
+            margin: 0;
+            padding: 0;
+            font-size: $global-font-size-18;
+            color: #fff;
+            text-align: center;
+            font-weight: normal;
+            font-style: normal;
+            text-decoration: none;
+            font-family: Tahoma;
+            line-height: 34px;
+            white-space: nowrap;
+            text-overflow: ellipsis;
+            -webkit-text-overflow: ellipsis;
+            -moz-text-overflow: ellipsis;
+            overflow: hidden;
+          }
+        }
+      }
+      .bottom {
+        margin: 10px 0;
+        font-size: $global-font-size-20;
+      }
+    }
+  }
+}
+</style>

+ 3 - 2
src/views/thirteen/index.vue

@@ -5,7 +5,7 @@
     </el-col>
     <el-col :span="24" class="two">
       <div class="w_1300 flex">
-        <el-col :span="11" class="two_1" v-for="(item, index) in list" :key="index" @click="toView(item)">
+        <el-col :span="8" class="two_1" v-for="(item, index) in list" :key="index" @click="toView(item)">
           <div class="top">
             <el-image class="image" :src="getUrl(item.file)" fit="fill" />
             <div class="text">
@@ -75,11 +75,12 @@ const getUrl = (item) => {
       justify-content: space-around;
     }
     .two_1 {
+      margin: 0 5px 0 0;
       .top {
         position: relative;
         .image {
           width: 100%;
-          height: 400px;
+          height: 300px;
         }
         .text {
           position: absolute;