zs 7 mesiacov pred
rodič
commit
7b2847a36d

+ 205 - 9
src/views/center/achievement.vue

@@ -38,7 +38,7 @@
         </el-col>
         </el-col>
       </el-col>
       </el-col>
     </el-row>
     </el-row>
-    <el-dialog v-model="dialog.show" :title="dialog.title" :destroy-on-close="false" @close="toClose">
+    <el-dialog v-model="dialog.show" :title="dialog.title" :destroy-on-close="false" @close="toClose" :width="width">
       <el-row>
       <el-row>
         <el-col :span="24" v-if="dialog.type == '1'">
         <el-col :span="24" v-if="dialog.type == '1'">
           <custom-form v-model="form" :fields="formFields" :rules="rules" @save="toSave" @draftSave="toDraftSave">
           <custom-form v-model="form" :fields="formFields" :rules="rules" @save="toSave" @draftSave="toDraftSave">
@@ -76,6 +76,39 @@
             </template>
             </template>
           </custom-form>
           </custom-form>
         </el-col>
         </el-col>
+        <transition name="why">
+          <el-col :span="24" v-if="dialog.type == '2'" class="dialog" v-loading="isLoading" element-loading-text="智能推荐中..." :element-loading-svg="svg" element-loading-svg-view-box="-10,-10,50,50">
+            <el-empty v-if="demandtotal == 0" description="暂无数据" />
+            <div class="list" v-for="(item, index) in demandList" :key="index" @click="toView(item)">
+              <h2 class="name textMore">
+                <span>{{ item.name || '暂无' }}</span>
+              </h2>
+              <div class="other">
+                <span class="other_1">{{ getDict(item.urgent, 'urgent') || '暂无' }}</span>
+                <div class="other_2">
+                  <span>应用行业:</span>
+                  {{ item.field || '暂无' }}
+                </div>
+                <div class="other_2">
+                  <span>资金预算:</span>
+                  {{ item.money || '面议' }}
+                </div>
+                <div class="other_2">
+                  <span>推荐指数:</span>
+                  <el-rate size="large" v-model="item._recommend" disabled show-score text-color="#ff9900" :score-template="`${item._recommend} 星`" />
+                </div>
+                <div class="other_2 textOne">
+                  <el-icon color="#0085f5"><Location /></el-icon>
+                  {{ getArea(item.area) }}
+                  <span class="state">{{ getDict(item.status, 'status') || '未解决' }}</span>
+                </div>
+              </div>
+            </div>
+            <el-col :span="24" class="page">
+              <el-pagination background layout="prev, pager, next" :total="demandtotal" :page-size="demandlimit" v-model:current-page="dcurrentPage" @current-change="dchangePage" @size-change="dsizeChange" />
+            </el-col>
+          </el-col>
+        </transition>
         <el-col :span="24" class="dialog_thr" v-if="dialog.type == '3'">
         <el-col :span="24" class="dialog_thr" v-if="dialog.type == '3'">
           <el-col :span="24" class="one">
           <el-col :span="24" class="one">
             <el-checkbox :indeterminate="isIndeterminate" v-model="checkAll" @change="handleCheckAllChange">全选</el-checkbox>
             <el-checkbox :indeterminate="isIndeterminate" v-model="checkAll" @change="handleCheckAllChange">全选</el-checkbox>
@@ -133,6 +166,8 @@ import { TagsStore } from '@/store/api/system/tags'
 import { SectorStore } from '@/store/api/platform/sector'
 import { SectorStore } from '@/store/api/platform/sector'
 import { RegionStore } from '@/store/api/system/region'
 import { RegionStore } from '@/store/api/system/region'
 import { UtilStore } from '@/store/api/util'
 import { UtilStore } from '@/store/api/util'
+import { EsStore } from '@/store/api/es'
+const esStore = EsStore()
 const utilStore = UtilStore()
 const utilStore = UtilStore()
 const regionStore = RegionStore()
 const regionStore = RegionStore()
 const store = AchievementStore()
 const store = AchievementStore()
@@ -161,6 +196,7 @@ const cityList = ref([])
 const achievementList = ref([])
 const achievementList = ref([])
 const tagsList = ref([])
 const tagsList = ref([])
 const sectorList = ref([])
 const sectorList = ref([])
+const urgentList = ref([])
 
 
 const form = ref({ file: [] })
 const form = ref({ file: [] })
 const dialog = ref({ type: '1', show: false, title: '发布成果' })
 const dialog = ref({ type: '1', show: false, title: '发布成果' })
@@ -192,6 +228,26 @@ const isIndeterminate = ref(true)
 // 导入文件
 // 导入文件
 const importActive = ref(0)
 const importActive = ref(0)
 const url = ref('')
 const url = ref('')
+
+const isLoading = ref(false)
+const router = useRouter()
+const svg = ref(`
+          <path class="path" d="
+            M 30 15
+            L 28 17
+            M 25.61 25.61
+            A 15 15, 0, 0, 1, 15 30
+            A 15 15, 0, 1, 1, 27.99 7.5
+            L 15 15
+          " style="stroke-width: 4px; fill: rgba(0, 0, 0, 0)"/>
+        `)
+// 推荐需求列表
+const demandList = ref([])
+let demandskip = 0
+let demandlimit = 4
+const demandtotal = ref(0)
+const key = ref('')
+const width = ref('50%')
 // 请求
 // 请求
 onMounted(async () => {
 onMounted(async () => {
   loading.value = true
   loading.value = true
@@ -240,6 +296,9 @@ const searchOther = async () => {
   // 成果状态
   // 成果状态
   result = await dictDataStore.query({ code: 'demandStatus', is_use: '0' })
   result = await dictDataStore.query({ code: 'demandStatus', is_use: '0' })
   if ($checkRes(result)) achievementList.value = result.data
   if ($checkRes(result)) achievementList.value = result.data
+  // 需求紧急度
+  result = await dictDataStore.query({ code: 'urgent', is_use: '0' })
+  if ($checkRes(result)) urgentList.value = result.data
   // 标签
   // 标签
   result = await tagsStore.query({ is_use: '0' })
   result = await tagsStore.query({ is_use: '0' })
   if ($checkRes(result)) tagsList.value = result.data
   if ($checkRes(result)) tagsList.value = result.data
@@ -255,6 +314,7 @@ const getDict = (data, model) => {
   if (data) {
   if (data) {
     let res
     let res
     if (model == 'status') res = statusList.value.find((f) => f.value == data)
     if (model == 'status') res = statusList.value.find((f) => f.value == data)
+    else if (model == 'urgent') res = urgentList.value.find((f) => f.value == data)
     return get(res, 'label')
     return get(res, 'label')
   }
   }
 }
 }
@@ -291,8 +351,12 @@ const toSave = async () => {
   if (get(data, 'id')) res = await store.update({ ...data, ...other })
   if (get(data, 'id')) res = await store.update({ ...data, ...other })
   else res = await store.create({ ...data, ...other })
   else res = await store.create({ ...data, ...other })
   if ($checkRes(res, true)) {
   if ($checkRes(res, true)) {
-    search({ skip, limit })
-    toClose()
+    key.value = form.value.name
+    await search({ skip, limit })
+    await toClose()
+    await searchDemand({ demandskip, demandlimit })
+    width.value = '90%'
+    dialog.value = { type: '2', show: true, title: '相关需求推荐' }
   }
   }
 }
 }
 const toDraftSave = async () => {
 const toDraftSave = async () => {
@@ -302,8 +366,12 @@ const toDraftSave = async () => {
   if (get(data, 'id')) res = await store.update({ ...data, ...other })
   if (get(data, 'id')) res = await store.update({ ...data, ...other })
   else res = await store.create({ ...data, ...other })
   else res = await store.create({ ...data, ...other })
   if ($checkRes(res, true)) {
   if ($checkRes(res, true)) {
-    search({ skip, limit })
-    toClose()
+    key.value = form.value.name
+    await search({ skip, limit })
+    await toClose()
+    await searchDemand({ demandskip, demandlimit })
+    width.value = '90%'
+    dialog.value = { type: '2', show: true, title: '相关需求推荐' }
   }
   }
 }
 }
 // 审核保存
 // 审核保存
@@ -313,18 +381,57 @@ const toExam = async (row) => {
       const data = cloneDeep(row)
       const data = cloneDeep(row)
       let res = await store.update({ id: data.id, status: '0', user: user.value.id })
       let res = await store.update({ id: data.id, status: '0', user: user.value.id })
       if ($checkRes(res, true)) {
       if ($checkRes(res, true)) {
-        search({ skip, limit })
-        toClose()
+        key.value = row.name
+        await search({ skip, limit })
+        await toClose()
+        await searchDemand({ demandskip, demandlimit })
+        width.value = '90%'
+        dialog.value = { type: '2', show: true, title: '相关需求推荐' }
       }
       }
     })
     })
     .catch(() => {})
     .catch(() => {})
 }
 }
+// 需求列表查询
+const searchDemand = async (query = { demandskip, demandlimit }) => {
+  demandskip = query.demandskip
+  demandlimit = query.demandlimit
+  isLoading.value = true
+  const info = { skip: demandskip, limit: demandlimit, keyword: key.value }
+  const res = await esStore.demand(info)
+  if (res.errcode == '0') {
+    demandList.value = res.data
+    demandtotal.value = res.total
+  }
+  setTimeout(() => {
+    isLoading.value = false
+  }, 3000) // 假设3秒后加载完成
+}
+const dcurrentPage = ref(1)
+// 分页
+const dchangePage = (page = dcurrentPage.value) => {
+  searchDemand({ demandskip: (page - 1) * demandlimit, demandlimit: demandlimit })
+}
+const dsizeChange = (limits) => {
+  demandlimit = limits
+  dcurrentPage.value = 1
+  searchDemand({ demandskip: 0, demandlimit: demandlimit })
+}
+// 地区
+const getArea = (data) => {
+  if (data) return data.join('-')
+  else return '暂无地区'
+}
+// 查看详情
+const toView = (item) => {
+  router.push({ path: '/demand/detail', query: { id: item.id || item._id } })
+}
 const toClose = () => {
 const toClose = () => {
   importActive.value = 0
   importActive.value = 0
   url.value = ''
   url.value = ''
   checkedExport.value = []
   checkedExport.value = []
   checkAll.value = false
   checkAll.value = false
-  form.value = { time: [] }
+  form.value = { file: [] }
+  width.value = '50%'
   dialog.value = { show: false }
   dialog.value = { show: false }
 }
 }
 // 全选
 // 全选
@@ -354,7 +461,7 @@ const toTemplate = () => {
 }
 }
 
 
 // 上传Excel
 // 上传Excel
-const onSuccess = async (response, file) => {
+const onSuccess = async (response) => {
   importActive.value = importActive.value + 1
   importActive.value = importActive.value + 1
   url.value = response.uri
   url.value = response.uri
 }
 }
@@ -435,6 +542,95 @@ const sizeChange = (limits) => {
     margin: 20px 0 0 0;
     margin: 20px 0 0 0;
   }
   }
 }
 }
+.why-enter-from,
+.why-leave-to {
+  opacity: 0;
+  transform: scale(0.6);
+}
+
+.why-enter-to,
+.why-leave-from {
+  opacity: 1;
+  transform: scale(1);
+}
+
+.why-enter-active,
+.why-leave-active {
+  transition: all 2s ease;
+}
+.dialog {
+  display: flex;
+  justify-content: space-between;
+  flex-wrap: wrap;
+  margin-top: 20px;
+  .list {
+    position: relative;
+    margin-right: 10px;
+    margin-bottom: 10px;
+    width: 380px;
+    box-shadow: 0 0 13px 0 rgba(5, 88, 219, 0.18);
+    .name {
+      padding: 10px 20px;
+      width: 380px;
+      height: 71px;
+      background-color: #dce5ff;
+      font-size: 16px;
+      line-height: 24px;
+      color: #0d0d0d;
+      display: flex;
+      align-items: center;
+    }
+    .other {
+      padding: 10px 20px 20px;
+      .other_1 {
+        padding: 0 10px;
+        height: 25px;
+        background-color: #e6f2fd;
+        border-radius: 2px;
+        border: solid 1px #cae0f5;
+        font-size: $global-font-size-14;
+        line-height: 25px;
+        color: #0085f5;
+      }
+      .other_2 {
+        display: flex;
+        align-items: center;
+        margin-top: 15px;
+        font-size: $global-font-size-16;
+        span {
+          color: #909090;
+        }
+        .state {
+          position: absolute;
+          right: 20px;
+          bottom: 15px;
+          display: inline-block;
+          vertical-align: middle;
+          padding: 0 20px;
+          height: 30px;
+          line-height: 30px;
+          background-image: linear-gradient(90deg, #ff8a00 0, #ff5a00 100%), linear-gradient(#ff7800, #ff7800);
+          background-blend-mode: normal, normal;
+          border-radius: 14px;
+          border: solid 1px #e5e5e5;
+          color: #fff;
+        }
+      }
+    }
+  }
+  .list:hover {
+    box-shadow: 0 0 5px 0 $global-color-107;
+    .name {
+      background-color: $global-color-107;
+      color: $global-color-fff;
+    }
+  }
+  .page {
+    margin: 10px 0;
+    display: flex;
+    justify-content: center;
+  }
+}
 .dialog_thr {
 .dialog_thr {
   padding: 20px;
   padding: 20px;
 
 

+ 47 - 13
src/views/center/demand.vue

@@ -71,6 +71,7 @@
         <!-- 加载界面 -->
         <!-- 加载界面 -->
         <transition name="why">
         <transition name="why">
           <el-col :span="24" v-if="dialog.type == '2'" class="dialog" v-loading="isLoading" element-loading-text="智能推荐中..." :element-loading-svg="svg" element-loading-svg-view-box="-10,-10,50,50">
           <el-col :span="24" v-if="dialog.type == '2'" class="dialog" v-loading="isLoading" element-loading-text="智能推荐中..." :element-loading-svg="svg" element-loading-svg-view-box="-10,-10,50,50">
+            <el-empty v-if="supplytotal == 0" description="暂无数据" />
             <div class="list" v-for="(item, index) in supplyList" :key="index" @click="toView(item)">
             <div class="list" v-for="(item, index) in supplyList" :key="index" @click="toView(item)">
               <h2 class="name textMore">
               <h2 class="name textMore">
                 <span>{{ item.name || '暂无' }}</span>
                 <span>{{ item.name || '暂无' }}</span>
@@ -89,8 +90,15 @@
                   <span>来源:</span>
                   <span>来源:</span>
                   {{ item.source || '暂无' }}
                   {{ item.source || '暂无' }}
                 </div>
                 </div>
+                <div class="other_2">
+                  <span>推荐指数:</span>
+                  <el-rate size="large" v-model="item._recommend" disabled show-score text-color="#ff9900" :score-template="`${item._recommend} 星`" />
+                </div>
               </div>
               </div>
             </div>
             </div>
+            <el-col :span="24" class="page">
+              <el-pagination background layout="prev, pager, next" :total="supplytotal" :page-size="supplylimit" v-model:current-page="scurrentPage" @current-change="schangePage" @size-change="ssizeChange" />
+            </el-col>
           </el-col>
           </el-col>
         </transition>
         </transition>
         <el-col :span="24" class="dialog_thr" v-if="dialog.type == '3'">
         <el-col :span="24" class="dialog_thr" v-if="dialog.type == '3'">
@@ -145,19 +153,19 @@ const userStore = UserStore()
 const user = computed(() => userStore.user)
 const user = computed(() => userStore.user)
 // 接口
 // 接口
 import { DemandStore } from '@/store/api/platform/demand'
 import { DemandStore } from '@/store/api/platform/demand'
-import { SupplyStore } from '@/store/api/platform/supply'
 import { DictDataStore } from '@/store/api/system/dictData'
 import { DictDataStore } from '@/store/api/system/dictData'
 import { TagsStore } from '@/store/api/system/tags'
 import { TagsStore } from '@/store/api/system/tags'
 import { SectorStore } from '@/store/api/platform/sector'
 import { SectorStore } from '@/store/api/platform/sector'
 import { RegionStore } from '@/store/api/system/region'
 import { RegionStore } from '@/store/api/system/region'
 import { UtilStore } from '@/store/api/util'
 import { UtilStore } from '@/store/api/util'
+import { EsStore } from '@/store/api/es'
+const esStore = EsStore()
 const utilStore = UtilStore()
 const utilStore = UtilStore()
 const regionStore = RegionStore()
 const regionStore = RegionStore()
 const store = DemandStore()
 const store = DemandStore()
 const dictDataStore = DictDataStore()
 const dictDataStore = DictDataStore()
 const tagsStore = TagsStore()
 const tagsStore = TagsStore()
 const sectorStore = SectorStore()
 const sectorStore = SectorStore()
-const supplyStore = SupplyStore()
 // 加载中
 // 加载中
 const loading = ref(false)
 const loading = ref(false)
 const isLoading = ref(false)
 const isLoading = ref(false)
@@ -192,6 +200,10 @@ const tagsList = ref([])
 const sectorList = ref([])
 const sectorList = ref([])
 // 推荐供给列表
 // 推荐供给列表
 const supplyList = ref([])
 const supplyList = ref([])
+let supplyskip = 0
+let supplylimit = 4
+const supplytotal = ref(0)
+const key = ref('')
 const width = ref('50%')
 const width = ref('50%')
 
 
 const form = ref({ time: [] })
 const form = ref({ time: [] })
@@ -319,9 +331,10 @@ const toSave = async () => {
   if (get(data, 'id')) res = await store.update({ ...data, ...other })
   if (get(data, 'id')) res = await store.update({ ...data, ...other })
   else res = await store.create({ ...data, ...other })
   else res = await store.create({ ...data, ...other })
   if ($checkRes(res, true)) {
   if ($checkRes(res, true)) {
+    key.value = form.value.name
     await search({ skip, limit })
     await search({ skip, limit })
     await toClose()
     await toClose()
-    await searchSupply()
+    await searchSupply({ supplyskip, supplylimit })
     width.value = '90%'
     width.value = '90%'
     dialog.value = { type: '2', show: true, title: '相关供给推荐' }
     dialog.value = { type: '2', show: true, title: '相关供给推荐' }
   }
   }
@@ -338,9 +351,10 @@ const toDraftSave = async () => {
   if (get(data, 'id')) res = await store.update({ ...data, ...other })
   if (get(data, 'id')) res = await store.update({ ...data, ...other })
   else res = await store.create({ ...data, ...other })
   else res = await store.create({ ...data, ...other })
   if ($checkRes(res, true)) {
   if ($checkRes(res, true)) {
+    key.value = form.value.name
     await search({ skip, limit })
     await search({ skip, limit })
     await toClose()
     await toClose()
-    await searchSupply()
+    await searchSupply({ supplyskip, supplylimit })
     width.value = '90%'
     width.value = '90%'
     dialog.value = { type: '2', show: true, title: '相关供给推荐' }
     dialog.value = { type: '2', show: true, title: '相关供给推荐' }
   }
   }
@@ -352,9 +366,10 @@ const toExam = async (row) => {
       const data = cloneDeep(row)
       const data = cloneDeep(row)
       let res = await store.update({ id: data.id, status: '0', user: user.value.id })
       let res = await store.update({ id: data.id, status: '0', user: user.value.id })
       if ($checkRes(res, true)) {
       if ($checkRes(res, true)) {
+        key.value = row.name
         await search({ skip, limit })
         await search({ skip, limit })
         await toClose()
         await toClose()
-        await searchSupply()
+        await searchSupply({ supplyskip, supplylimit })
         width.value = '90%'
         width.value = '90%'
         dialog.value = { type: '2', show: true, title: '相关供给推荐' }
         dialog.value = { type: '2', show: true, title: '相关供给推荐' }
       }
       }
@@ -362,15 +377,30 @@ const toExam = async (row) => {
     .catch(() => {})
     .catch(() => {})
 }
 }
 // 供给列表查询
 // 供给列表查询
-const searchSupply = async () => {
+const searchSupply = async (query = { supplyskip, supplylimit }) => {
+  supplyskip = query.supplyskip
+  supplylimit = query.supplylimit
   isLoading.value = true
   isLoading.value = true
-  const info = { skip: 0, limit: 5, is_use: '0', status: '1' }
-  const res = await supplyStore.query(info)
-  if (res.errcode == '0') supplyList.value = res.data
+  const info = { skip: supplyskip, limit: supplylimit, keyword: key.value }
+  const res = await esStore.supply(info)
+  if (res.errcode == '0') {
+    supplyList.value = res.data
+    supplytotal.value = res.total
+  }
   setTimeout(() => {
   setTimeout(() => {
     isLoading.value = false
     isLoading.value = false
   }, 3000) // 假设3秒后加载完成
   }, 3000) // 假设3秒后加载完成
 }
 }
+const scurrentPage = ref(1)
+// 分页
+const schangePage = (page = scurrentPage.value) => {
+  searchSupply({ supplyskip: (page - 1) * supplylimit, supplylimit: supplylimit })
+}
+const ssizeChange = (limits) => {
+  supplylimit = limits
+  scurrentPage.value = 1
+  searchSupply({ supplyskip: 0, supplylimit: supplylimit })
+}
 // 查看详情
 // 查看详情
 const toView = (item) => {
 const toView = (item) => {
   router.push({ path: '/supply/detail', query: { id: item.id || item._id } })
   router.push({ path: '/supply/detail', query: { id: item.id || item._id } })
@@ -411,7 +441,7 @@ const toTemplate = () => {
 }
 }
 
 
 // 上传Excel
 // 上传Excel
-const onSuccess = async (response, file) => {
+const onSuccess = async (response) => {
   importActive.value = importActive.value + 1
   importActive.value = importActive.value + 1
   url.value = response.uri
   url.value = response.uri
 }
 }
@@ -515,7 +545,6 @@ const sizeChange = (limits) => {
     margin-right: 10px;
     margin-right: 10px;
     margin-bottom: 10px;
     margin-bottom: 10px;
     width: 380px;
     width: 380px;
-    height: 233px;
     box-shadow: 0 0 13px 0 rgba(5, 88, 219, 0.18);
     box-shadow: 0 0 13px 0 rgba(5, 88, 219, 0.18);
     .name {
     .name {
       padding: 10px 20px;
       padding: 10px 20px;
@@ -529,8 +558,7 @@ const sizeChange = (limits) => {
       align-items: center;
       align-items: center;
     }
     }
     .other {
     .other {
-      height: 162px;
-      padding: 10px 20px 0 20px;
+      padding: 10px 20px 20px;
       .other_1 {
       .other_1 {
         padding: 0 10px;
         padding: 0 10px;
         height: 25px;
         height: 25px;
@@ -543,6 +571,7 @@ const sizeChange = (limits) => {
       }
       }
       .other_2 {
       .other_2 {
         display: flex;
         display: flex;
+        justify-content: space-between;
         align-items: center;
         align-items: center;
         margin-top: 15px;
         margin-top: 15px;
         font-size: $global-font-size-16;
         font-size: $global-font-size-16;
@@ -574,6 +603,11 @@ const sizeChange = (limits) => {
       color: $global-color-fff;
       color: $global-color-fff;
     }
     }
   }
   }
+  .page {
+    margin: 10px 0;
+    display: flex;
+    justify-content: center;
+  }
 }
 }
 .dialog_thr {
 .dialog_thr {
   padding: 20px;
   padding: 20px;

+ 47 - 13
src/views/center/project.vue

@@ -78,6 +78,7 @@
         </el-col>
         </el-col>
         <transition name="why">
         <transition name="why">
           <el-col :span="24" v-if="dialog.type == '2'" class="dialog" v-loading="isLoading" element-loading-text="智能推荐中..." :element-loading-svg="svg" element-loading-svg-view-box="-10,-10,50,50">
           <el-col :span="24" v-if="dialog.type == '2'" class="dialog" v-loading="isLoading" element-loading-text="智能推荐中..." :element-loading-svg="svg" element-loading-svg-view-box="-10,-10,50,50">
+            <el-empty v-if="demandtotal == 0" description="暂无数据" />
             <div class="list" v-for="(item, index) in demandList" :key="index" @click="toView(item)">
             <div class="list" v-for="(item, index) in demandList" :key="index" @click="toView(item)">
               <h2 class="name textMore">
               <h2 class="name textMore">
                 <span>{{ item.name || '暂无' }}</span>
                 <span>{{ item.name || '暂无' }}</span>
@@ -92,6 +93,10 @@
                   <span>资金预算:</span>
                   <span>资金预算:</span>
                   {{ item.money || '面议' }}
                   {{ item.money || '面议' }}
                 </div>
                 </div>
+                <div class="other_2">
+                  <span>推荐指数:</span>
+                  <el-rate size="large" v-model="item._recommend" disabled show-score text-color="#ff9900" :score-template="`${item._recommend} 星`" />
+                </div>
                 <div class="other_2 textOne">
                 <div class="other_2 textOne">
                   <el-icon color="#0085f5"><Location /></el-icon>
                   <el-icon color="#0085f5"><Location /></el-icon>
                   {{ getArea(item.area) }}
                   {{ getArea(item.area) }}
@@ -99,6 +104,9 @@
                 </div>
                 </div>
               </div>
               </div>
             </div>
             </div>
+            <el-col :span="24" class="page">
+              <el-pagination background layout="prev, pager, next" :total="demandtotal" :page-size="demandlimit" v-model:current-page="dcurrentPage" @current-change="dchangePage" @size-change="dsizeChange" />
+            </el-col>
           </el-col>
           </el-col>
         </transition>
         </transition>
         <el-col :span="24" class="dialog_thr" v-if="dialog.type == '3'">
         <el-col :span="24" class="dialog_thr" v-if="dialog.type == '3'">
@@ -153,19 +161,19 @@ const userStore = UserStore()
 const user = computed(() => userStore.user)
 const user = computed(() => userStore.user)
 // 接口
 // 接口
 import { ProjectStore } from '@/store/api/platform/project'
 import { ProjectStore } from '@/store/api/platform/project'
-import { DemandStore } from '@/store/api/platform/demand'
 import { DictDataStore } from '@/store/api/system/dictData'
 import { DictDataStore } from '@/store/api/system/dictData'
 import { TagsStore } from '@/store/api/system/tags'
 import { TagsStore } from '@/store/api/system/tags'
 import { SectorStore } from '@/store/api/platform/sector'
 import { SectorStore } from '@/store/api/platform/sector'
 import { RegionStore } from '@/store/api/system/region'
 import { RegionStore } from '@/store/api/system/region'
 import { UtilStore } from '@/store/api/util'
 import { UtilStore } from '@/store/api/util'
+import { EsStore } from '@/store/api/es'
+const esStore = EsStore()
 const utilStore = UtilStore()
 const utilStore = UtilStore()
 const regionStore = RegionStore()
 const regionStore = RegionStore()
 const store = ProjectStore()
 const store = ProjectStore()
 const dictDataStore = DictDataStore()
 const dictDataStore = DictDataStore()
 const tagsStore = TagsStore()
 const tagsStore = TagsStore()
 const sectorStore = SectorStore()
 const sectorStore = SectorStore()
-const demandStore = DemandStore()
 // 加载中
 // 加载中
 const loading = ref(false)
 const loading = ref(false)
 const isLoading = ref(false)
 const isLoading = ref(false)
@@ -201,6 +209,10 @@ const sectorList = ref([])
 
 
 // 推荐需求列表
 // 推荐需求列表
 const demandList = ref([])
 const demandList = ref([])
+let demandskip = 0
+let demandlimit = 4
+const demandtotal = ref(0)
+const key = ref('')
 const width = ref('50%')
 const width = ref('50%')
 
 
 const form = ref({ file: [] })
 const form = ref({ file: [] })
@@ -327,9 +339,10 @@ const toSave = async () => {
   if (get(data, 'id')) res = await store.update({ ...data, ...other })
   if (get(data, 'id')) res = await store.update({ ...data, ...other })
   else res = await store.create({ ...data, ...other })
   else res = await store.create({ ...data, ...other })
   if ($checkRes(res, true)) {
   if ($checkRes(res, true)) {
+    key.value = form.value.name
     await search({ skip, limit })
     await search({ skip, limit })
     await toClose()
     await toClose()
-    await searchDemand()
+    await searchDemand({ demandskip, demandlimit })
     width.value = '90%'
     width.value = '90%'
     dialog.value = { type: '2', show: true, title: '相关需求推荐' }
     dialog.value = { type: '2', show: true, title: '相关需求推荐' }
   }
   }
@@ -341,9 +354,10 @@ const toDraftSave = async () => {
   if (get(data, 'id')) res = await store.update({ ...data, ...other })
   if (get(data, 'id')) res = await store.update({ ...data, ...other })
   else res = await store.create({ ...data, ...other })
   else res = await store.create({ ...data, ...other })
   if ($checkRes(res, true)) {
   if ($checkRes(res, true)) {
+    key.value = form.value.name
     await search({ skip, limit })
     await search({ skip, limit })
     await toClose()
     await toClose()
-    await searchDemand()
+    await searchDemand({ demandskip, demandlimit })
     width.value = '90%'
     width.value = '90%'
     dialog.value = { type: '2', show: true, title: '相关需求推荐' }
     dialog.value = { type: '2', show: true, title: '相关需求推荐' }
   }
   }
@@ -355,9 +369,10 @@ const toExam = async (row) => {
       const data = cloneDeep(row)
       const data = cloneDeep(row)
       let res = await store.update({ id: data.id, status: '0', user: user.value.id })
       let res = await store.update({ id: data.id, status: '0', user: user.value.id })
       if ($checkRes(res, true)) {
       if ($checkRes(res, true)) {
+        key.value = row.name
         await search({ skip, limit })
         await search({ skip, limit })
         await toClose()
         await toClose()
-        await searchDemand()
+        await searchDemand({ demandskip, demandlimit })
         width.value = '90%'
         width.value = '90%'
         dialog.value = { type: '2', show: true, title: '相关需求推荐' }
         dialog.value = { type: '2', show: true, title: '相关需求推荐' }
       }
       }
@@ -365,15 +380,30 @@ const toExam = async (row) => {
     .catch(() => {})
     .catch(() => {})
 }
 }
 // 需求列表查询
 // 需求列表查询
-const searchDemand = async () => {
+const searchDemand = async (query = { demandskip, demandlimit }) => {
+  demandskip = query.demandskip
+  demandlimit = query.demandlimit
   isLoading.value = true
   isLoading.value = true
-  const info = { skip: 0, limit: 5, is_use: '0', status: '1' }
-  const res = await demandStore.query(info)
-  if (res.errcode == '0') demandList.value = res.data
+  const info = { skip: demandskip, limit: demandlimit, keyword: key.value }
+  const res = await esStore.demand(info)
+  if (res.errcode == '0') {
+    demandList.value = res.data
+    demandtotal.value = res.total
+  }
   setTimeout(() => {
   setTimeout(() => {
     isLoading.value = false
     isLoading.value = false
   }, 3000) // 假设3秒后加载完成
   }, 3000) // 假设3秒后加载完成
 }
 }
+const dcurrentPage = ref(1)
+// 分页
+const dchangePage = (page = dcurrentPage.value) => {
+  searchDemand({ demandskip: (page - 1) * demandlimit, demandlimit: demandlimit })
+}
+const dsizeChange = (limits) => {
+  demandlimit = limits
+  dcurrentPage.value = 1
+  searchDemand({ demandskip: 0, demandlimit: demandlimit })
+}
 // 查看详情
 // 查看详情
 const toView = (item) => {
 const toView = (item) => {
   router.push({ path: '/demand/detail', query: { id: item.id || item._id } })
   router.push({ path: '/demand/detail', query: { id: item.id || item._id } })
@@ -419,7 +449,7 @@ const toTemplate = () => {
 }
 }
 
 
 // 上传Excel
 // 上传Excel
-const onSuccess = async (response, file) => {
+const onSuccess = async (response) => {
   importActive.value = importActive.value + 1
   importActive.value = importActive.value + 1
   url.value = response.uri
   url.value = response.uri
 }
 }
@@ -517,6 +547,7 @@ const sizeChange = (limits) => {
 }
 }
 .dialog {
 .dialog {
   display: flex;
   display: flex;
+  justify-content: space-between;
   flex-wrap: wrap;
   flex-wrap: wrap;
   margin-top: 20px;
   margin-top: 20px;
   .list {
   .list {
@@ -524,7 +555,6 @@ const sizeChange = (limits) => {
     margin-right: 10px;
     margin-right: 10px;
     margin-bottom: 10px;
     margin-bottom: 10px;
     width: 380px;
     width: 380px;
-    height: 233px;
     box-shadow: 0 0 13px 0 rgba(5, 88, 219, 0.18);
     box-shadow: 0 0 13px 0 rgba(5, 88, 219, 0.18);
     .name {
     .name {
       padding: 10px 20px;
       padding: 10px 20px;
@@ -538,8 +568,7 @@ const sizeChange = (limits) => {
       align-items: center;
       align-items: center;
     }
     }
     .other {
     .other {
-      height: 162px;
-      padding: 10px 20px 0 20px;
+      padding: 10px 20px 20px;
       .other_1 {
       .other_1 {
         padding: 0 10px;
         padding: 0 10px;
         height: 25px;
         height: 25px;
@@ -583,6 +612,11 @@ const sizeChange = (limits) => {
       color: $global-color-fff;
       color: $global-color-fff;
     }
     }
   }
   }
+  .page {
+    margin: 10px 0;
+    display: flex;
+    justify-content: center;
+  }
 }
 }
 .dialog_thr {
 .dialog_thr {
   padding: 20px;
   padding: 20px;

+ 48 - 14
src/views/center/supply.vue

@@ -70,6 +70,7 @@
         </el-col>
         </el-col>
         <transition name="why">
         <transition name="why">
           <el-col :span="24" v-if="dialog.type == '2'" class="dialog" v-loading="isLoading" element-loading-text="智能推荐中..." :element-loading-svg="svg" element-loading-svg-view-box="-10,-10,50,50">
           <el-col :span="24" v-if="dialog.type == '2'" class="dialog" v-loading="isLoading" element-loading-text="智能推荐中..." :element-loading-svg="svg" element-loading-svg-view-box="-10,-10,50,50">
+            <el-empty v-if="demandtotal == 0" description="暂无数据" />
             <div class="list" v-for="(item, index) in demandList" :key="index" @click="toView(item)">
             <div class="list" v-for="(item, index) in demandList" :key="index" @click="toView(item)">
               <h2 class="name textMore">
               <h2 class="name textMore">
                 <span>{{ item.name || '暂无' }}</span>
                 <span>{{ item.name || '暂无' }}</span>
@@ -84,6 +85,10 @@
                   <span>资金预算:</span>
                   <span>资金预算:</span>
                   {{ item.money || '面议' }}
                   {{ item.money || '面议' }}
                 </div>
                 </div>
+                <div class="other_2">
+                  <span>推荐指数:</span>
+                  <el-rate size="large" v-model="item._recommend" disabled show-score text-color="#ff9900" :score-template="`${item._recommend} 星`" />
+                </div>
                 <div class="other_2 textOne">
                 <div class="other_2 textOne">
                   <el-icon color="#0085f5"><Location /></el-icon>
                   <el-icon color="#0085f5"><Location /></el-icon>
                   {{ getArea(item.area) }}
                   {{ getArea(item.area) }}
@@ -91,6 +96,9 @@
                 </div>
                 </div>
               </div>
               </div>
             </div>
             </div>
+            <el-col :span="24" class="page">
+              <el-pagination background layout="prev, pager, next" :total="demandtotal" :page-size="demandlimit" v-model:current-page="dcurrentPage" @current-change="dchangePage" @size-change="dsizeChange" />
+            </el-col>
           </el-col>
           </el-col>
         </transition>
         </transition>
         <el-col :span="24" class="dialog_thr" v-if="dialog.type == '3'">
         <el-col :span="24" class="dialog_thr" v-if="dialog.type == '3'">
@@ -145,19 +153,19 @@ const userStore = UserStore()
 const user = computed(() => userStore.user)
 const user = computed(() => userStore.user)
 // 接口
 // 接口
 import { SupplyStore } from '@/store/api/platform/supply'
 import { SupplyStore } from '@/store/api/platform/supply'
-import { DemandStore } from '@/store/api/platform/demand'
 import { DictDataStore } from '@/store/api/system/dictData'
 import { DictDataStore } from '@/store/api/system/dictData'
 import { TagsStore } from '@/store/api/system/tags'
 import { TagsStore } from '@/store/api/system/tags'
 import { SectorStore } from '@/store/api/platform/sector'
 import { SectorStore } from '@/store/api/platform/sector'
 import { RegionStore } from '@/store/api/system/region'
 import { RegionStore } from '@/store/api/system/region'
 import { UtilStore } from '@/store/api/util'
 import { UtilStore } from '@/store/api/util'
+import { EsStore } from '@/store/api/es'
+const esStore = EsStore()
 const utilStore = UtilStore()
 const utilStore = UtilStore()
 const regionStore = RegionStore()
 const regionStore = RegionStore()
 const store = SupplyStore()
 const store = SupplyStore()
 const dictDataStore = DictDataStore()
 const dictDataStore = DictDataStore()
 const tagsStore = TagsStore()
 const tagsStore = TagsStore()
 const sectorStore = SectorStore()
 const sectorStore = SectorStore()
-const demandStore = DemandStore()
 // 加载中
 // 加载中
 const loading = ref(false)
 const loading = ref(false)
 const isLoading = ref(false)
 const isLoading = ref(false)
@@ -192,6 +200,10 @@ const sectorList = ref([])
 
 
 // 推荐需求列表
 // 推荐需求列表
 const demandList = ref([])
 const demandList = ref([])
+let demandskip = 0
+let demandlimit = 4
+const demandtotal = ref(0)
+const key = ref('')
 const width = ref('50%')
 const width = ref('50%')
 
 
 const form = ref({ time: [] })
 const form = ref({ time: [] })
@@ -312,9 +324,10 @@ const toSave = async () => {
   if (get(data, 'id')) res = await store.update({ ...data, ...other })
   if (get(data, 'id')) res = await store.update({ ...data, ...other })
   else res = await store.create({ ...data, ...other })
   else res = await store.create({ ...data, ...other })
   if ($checkRes(res, true)) {
   if ($checkRes(res, true)) {
+    key.value = form.value.name
     await search({ skip, limit })
     await search({ skip, limit })
     await toClose()
     await toClose()
-    await searchDemand()
+    await searchDemand({ demandskip, demandlimit })
     width.value = '90%'
     width.value = '90%'
     dialog.value = { type: '2', show: true, title: '相关需求推荐' }
     dialog.value = { type: '2', show: true, title: '相关需求推荐' }
   }
   }
@@ -331,9 +344,10 @@ const toDraftSave = async () => {
   if (get(data, 'id')) res = await store.update({ ...data, ...other })
   if (get(data, 'id')) res = await store.update({ ...data, ...other })
   else res = await store.create({ ...data, ...other })
   else res = await store.create({ ...data, ...other })
   if ($checkRes(res, true)) {
   if ($checkRes(res, true)) {
+    key.value = form.value.name
     await search({ skip, limit })
     await search({ skip, limit })
     await toClose()
     await toClose()
-    await searchDemand()
+    await searchDemand({ demandskip, demandlimit })
     width.value = '90%'
     width.value = '90%'
     dialog.value = { type: '2', show: true, title: '相关需求推荐' }
     dialog.value = { type: '2', show: true, title: '相关需求推荐' }
   }
   }
@@ -345,9 +359,10 @@ const toExam = async (row) => {
       const data = cloneDeep(row)
       const data = cloneDeep(row)
       let res = await store.update({ id: data.id, status: '0', user: user.value.id })
       let res = await store.update({ id: data.id, status: '0', user: user.value.id })
       if ($checkRes(res, true)) {
       if ($checkRes(res, true)) {
+        key.value = row.name
         await search({ skip, limit })
         await search({ skip, limit })
         await toClose()
         await toClose()
-        await searchDemand()
+        await searchDemand({ demandskip, demandlimit })
         width.value = '90%'
         width.value = '90%'
         dialog.value = { type: '2', show: true, title: '相关需求推荐' }
         dialog.value = { type: '2', show: true, title: '相关需求推荐' }
       }
       }
@@ -355,18 +370,33 @@ const toExam = async (row) => {
     .catch(() => {})
     .catch(() => {})
 }
 }
 // 需求列表查询
 // 需求列表查询
-const searchDemand = async () => {
+const searchDemand = async (query = { demandskip, demandlimit }) => {
+  demandskip = query.demandskip
+  demandlimit = query.demandlimit
   isLoading.value = true
   isLoading.value = true
-  const info = { skip: 0, limit: 5, is_use: '0', status: '1' }
-  const res = await demandStore.query(info)
-  if (res.errcode == '0') demandList.value = res.data
+  const info = { skip: demandskip, limit: demandlimit, keyword: key.value }
+  const res = await esStore.demand(info)
+  if (res.errcode == '0') {
+    demandList.value = res.data
+    demandtotal.value = res.total
+  }
   setTimeout(() => {
   setTimeout(() => {
     isLoading.value = false
     isLoading.value = false
   }, 3000) // 假设3秒后加载完成
   }, 3000) // 假设3秒后加载完成
 }
 }
+const dcurrentPage = ref(1)
+// 分页
+const dchangePage = (page = dcurrentPage.value) => {
+  searchDemand({ demandskip: (page - 1) * demandlimit, demandlimit: demandlimit })
+}
+const dsizeChange = (limits) => {
+  demandlimit = limits
+  dcurrentPage.value = 1
+  searchDemand({ demandskip: 0, demandlimit: demandlimit })
+}
 // 查看详情
 // 查看详情
 const toView = (item) => {
 const toView = (item) => {
-  router.push({ path: '/supply/detail', query: { id: item.id || item._id } })
+  router.push({ path: '/demand/detail', query: { id: item.id || item._id } })
 }
 }
 // 地区
 // 地区
 const getArea = (data) => {
 const getArea = (data) => {
@@ -407,7 +437,7 @@ const toTemplate = () => {
 }
 }
 
 
 // 上传Excel
 // 上传Excel
-const onSuccess = async (response, file) => {
+const onSuccess = async (response) => {
   importActive.value = importActive.value + 1
   importActive.value = importActive.value + 1
   url.value = response.uri
   url.value = response.uri
 }
 }
@@ -505,6 +535,7 @@ const sizeChange = (limits) => {
 }
 }
 .dialog {
 .dialog {
   display: flex;
   display: flex;
+  justify-content: space-between;
   flex-wrap: wrap;
   flex-wrap: wrap;
   margin-top: 20px;
   margin-top: 20px;
   .list {
   .list {
@@ -512,7 +543,6 @@ const sizeChange = (limits) => {
     margin-right: 10px;
     margin-right: 10px;
     margin-bottom: 10px;
     margin-bottom: 10px;
     width: 380px;
     width: 380px;
-    height: 233px;
     box-shadow: 0 0 13px 0 rgba(5, 88, 219, 0.18);
     box-shadow: 0 0 13px 0 rgba(5, 88, 219, 0.18);
     .name {
     .name {
       padding: 10px 20px;
       padding: 10px 20px;
@@ -526,8 +556,7 @@ const sizeChange = (limits) => {
       align-items: center;
       align-items: center;
     }
     }
     .other {
     .other {
-      height: 162px;
-      padding: 10px 20px 0 20px;
+      padding: 10px 20px 20px;
       .other_1 {
       .other_1 {
         padding: 0 10px;
         padding: 0 10px;
         height: 25px;
         height: 25px;
@@ -571,6 +600,11 @@ const sizeChange = (limits) => {
       color: $global-color-fff;
       color: $global-color-fff;
     }
     }
   }
   }
+  .page {
+    margin: 10px 0;
+    display: flex;
+    justify-content: center;
+  }
 }
 }
 .dialog_thr {
 .dialog_thr {
   padding: 20px;
   padding: 20px;

+ 213 - 3
src/views/two/add/achievement.vue

@@ -38,10 +38,48 @@
         </custom-form>
         </custom-form>
       </el-col>
       </el-col>
     </el-row>
     </el-row>
+    <el-dialog v-model="dialog.show" :title="dialog.title" :destroy-on-close="false" @close="toClose" :width="width">
+      <el-row>
+        <transition name="why">
+          <el-col :span="24" v-if="dialog.type == '2'" class="dialog" v-loading="isLoading" element-loading-text="智能推荐中..." :element-loading-svg="svg" element-loading-svg-view-box="-10,-10,50,50">
+            <el-empty v-if="demandtotal == 0" description="暂无数据" />
+            <div class="list" v-for="(item, index) in demandList" :key="index" @click="toView(item)">
+              <h2 class="name textMore">
+                <span>{{ item.name || '暂无' }}</span>
+              </h2>
+              <div class="other">
+                <span class="other_1">{{ getDict(item.urgent, 'urgent') || '暂无' }}</span>
+                <div class="other_2">
+                  <span>应用行业:</span>
+                  {{ item.field || '暂无' }}
+                </div>
+                <div class="other_2">
+                  <span>资金预算:</span>
+                  {{ item.money || '面议' }}
+                </div>
+                <div class="other_2">
+                  <span>推荐指数:</span>
+                  <el-rate size="large" v-model="item._recommend" disabled show-score text-color="#ff9900" :score-template="`${item._recommend} 星`" />
+                </div>
+                <div class="other_2 textOne">
+                  <el-icon color="#0085f5"><Location /></el-icon>
+                  {{ getArea(item.area) }}
+                  <span class="state">{{ getDict(item.status, 'status') || '未解决' }}</span>
+                </div>
+              </div>
+            </div>
+            <el-col :span="24" class="page">
+              <el-pagination background layout="prev, pager, next" :total="demandtotal" :page-size="demandlimit" v-model:current-page="dcurrentPage" @current-change="dchangePage" @size-change="dsizeChange" />
+            </el-col>
+          </el-col>
+        </transition>
+      </el-row>
+    </el-dialog>
   </div>
   </div>
 </template>
 </template>
 
 
 <script setup>
 <script setup>
+const router = useRouter()
 import { cloneDeep, get } from 'lodash-es'
 import { cloneDeep, get } from 'lodash-es'
 const $checkRes = inject('$checkRes')
 const $checkRes = inject('$checkRes')
 import { UserStore } from '@/store/user'
 import { UserStore } from '@/store/user'
@@ -53,6 +91,8 @@ import { DictDataStore } from '@/store/api/system/dictData'
 import { TagsStore } from '@/store/api/system/tags'
 import { TagsStore } from '@/store/api/system/tags'
 import { SectorStore } from '@/store/api/platform/sector'
 import { SectorStore } from '@/store/api/platform/sector'
 import { RegionStore } from '@/store/api/system/region'
 import { RegionStore } from '@/store/api/system/region'
+import { EsStore } from '@/store/api/es'
+const esStore = EsStore()
 const regionStore = RegionStore()
 const regionStore = RegionStore()
 const store = AchievementStore()
 const store = AchievementStore()
 const dictDataStore = DictDataStore()
 const dictDataStore = DictDataStore()
@@ -72,6 +112,7 @@ const cityList = ref([])
 const achievementList = ref([])
 const achievementList = ref([])
 const tagsList = ref([])
 const tagsList = ref([])
 const sectorList = ref([])
 const sectorList = ref([])
+const urgentList = ref([])
 const formFields = ref([
 const formFields = ref([
   { label: '成果名称', model: 'name' },
   { label: '成果名称', model: 'name' },
   { label: '标签', model: 'tags', custom: true, mark: 'tags' },
   { label: '标签', model: 'tags', custom: true, mark: 'tags' },
@@ -94,6 +135,26 @@ const formFields = ref([
 ])
 ])
 const form = ref({ file: [] })
 const form = ref({ file: [] })
 const rules = reactive({ name: [{ required: true, message: '请输入成果名称', trigger: 'blur' }] })
 const rules = reactive({ name: [{ required: true, message: '请输入成果名称', trigger: 'blur' }] })
+// 加载中
+const isLoading = ref(false)
+const svg = ref(`
+          <path class="path" d="
+            M 30 15
+            L 28 17
+            M 25.61 25.61
+            A 15 15, 0, 0, 1, 15 30
+            A 15 15, 0, 1, 1, 27.99 7.5
+            L 15 15
+          " style="stroke-width: 4px; fill: rgba(0, 0, 0, 0)"/>
+        `)
+// 推荐需求列表
+const demandList = ref([])
+let demandskip = 0
+let demandlimit = 4
+const demandtotal = ref(0)
+const key = ref('')
+const width = ref('50%')
+const dialog = ref({ type: '1', show: false, title: '需求智能推荐' })
 // 请求
 // 请求
 onMounted(async () => {
 onMounted(async () => {
   loading.value = true
   loading.value = true
@@ -135,6 +196,9 @@ const searchOther = async () => {
   // 城市
   // 城市
   result = await regionStore.area({ level: 'province', code: 22 })
   result = await regionStore.area({ level: 'province', code: 22 })
   if ($checkRes(result)) cityList.value = result.data
   if ($checkRes(result)) cityList.value = result.data
+  // 需求紧急度
+  result = await dictDataStore.query({ code: 'urgent', is_use: '0' })
+  if ($checkRes(result)) urgentList.value = result.data
 }
 }
 // 上传图片
 // 上传图片
 const onUpload = (e) => {
 const onUpload = (e) => {
@@ -149,7 +213,11 @@ const toSave = async () => {
   else res = await store.create({ ...data, ...other })
   else res = await store.create({ ...data, ...other })
   if ($checkRes(res, true)) {
   if ($checkRes(res, true)) {
     ElMessage({ message: `发布成功可以长历史发布查看`, type: 'success' })
     ElMessage({ message: `发布成功可以长历史发布查看`, type: 'success' })
-    form.value = {}
+    key.value = form.value.name
+    await toClose()
+    await searchDemand({ demandskip, demandlimit })
+    width.value = '90%'
+    dialog.value = { type: '2', show: true, title: '相关需求推荐' }
   }
   }
 }
 }
 const toDraftSave = async () => {
 const toDraftSave = async () => {
@@ -160,8 +228,150 @@ const toDraftSave = async () => {
   else res = await store.create({ ...data, ...other })
   else res = await store.create({ ...data, ...other })
   if ($checkRes(res, true)) {
   if ($checkRes(res, true)) {
     ElMessage({ message: `发布成功可以长历史发布查看`, type: 'success' })
     ElMessage({ message: `发布成功可以长历史发布查看`, type: 'success' })
-    form.value = {}
+    key.value = form.value.name
+    await toClose()
+    await searchDemand({ demandskip, demandlimit })
+    width.value = '90%'
+    dialog.value = { type: '2', show: true, title: '相关需求推荐' }
+  }
+}
+const toClose = () => {
+  form.value = {}
+  width.value = '50%'
+  dialog.value = { show: false }
+}
+// 地区
+const getArea = (data) => {
+  if (data) return data.join('-')
+  else return '暂无地区'
+}
+// 字典数据转换
+const getDict = (data, model) => {
+  if (data) {
+    let res
+    if (model == 'status') res = statusList.value.find((f) => f.value == data)
+    else if (model == 'urgent') res = urgentList.value.find((f) => f.value == data)
+    return get(res, 'label')
   }
   }
 }
 }
+// 需求列表查询
+const searchDemand = async (query = { demandskip, demandlimit }) => {
+  demandskip = query.demandskip
+  demandlimit = query.demandlimit
+  isLoading.value = true
+  const info = { skip: demandskip, limit: demandlimit, keyword: key.value }
+  const res = await esStore.demand(info)
+  if (res.errcode == '0') {
+    demandList.value = res.data
+    demandtotal.value = res.total
+  }
+  setTimeout(() => {
+    isLoading.value = false
+  }, 3000) // 假设3秒后加载完成
+}
+// 查看详情
+const toView = (item) => {
+  router.push({ path: '/demand/detail', query: { id: item.id || item._id } })
+}
+const dcurrentPage = ref(1)
+// 分页
+const dchangePage = (page = dcurrentPage.value) => {
+  searchDemand({ demandskip: (page - 1) * demandlimit, demandlimit: demandlimit })
+}
+const dsizeChange = (limits) => {
+  demandlimit = limits
+  dcurrentPage.value = 1
+  searchDemand({ demandskip: 0, demandlimit: demandlimit })
+}
 </script>
 </script>
-<style scoped lang="scss"></style>
+<style scoped lang="scss">
+.why-enter-from,
+.why-leave-to {
+  opacity: 0;
+  transform: scale(0.6);
+}
+
+.why-enter-to,
+.why-leave-from {
+  opacity: 1;
+  transform: scale(1);
+}
+
+.why-enter-active,
+.why-leave-active {
+  transition: all 2s ease;
+}
+.dialog {
+  display: flex;
+  justify-content: space-between;
+  flex-wrap: wrap;
+  margin-top: 20px;
+  .list {
+    position: relative;
+    margin-right: 10px;
+    margin-bottom: 10px;
+    width: 380px;
+    box-shadow: 0 0 13px 0 rgba(5, 88, 219, 0.18);
+    .name {
+      padding: 10px 20px;
+      width: 380px;
+      height: 71px;
+      background-color: #dce5ff;
+      font-size: 16px;
+      line-height: 24px;
+      color: #0d0d0d;
+      display: flex;
+      align-items: center;
+    }
+    .other {
+      padding: 10px 20px 20px;
+      .other_1 {
+        padding: 0 10px;
+        height: 25px;
+        background-color: #e6f2fd;
+        border-radius: 2px;
+        border: solid 1px #cae0f5;
+        font-size: $global-font-size-14;
+        line-height: 25px;
+        color: #0085f5;
+      }
+      .other_2 {
+        display: flex;
+        align-items: center;
+        margin-top: 15px;
+        font-size: $global-font-size-16;
+        span {
+          color: #909090;
+        }
+        .state {
+          position: absolute;
+          right: 20px;
+          bottom: 15px;
+          display: inline-block;
+          vertical-align: middle;
+          padding: 0 20px;
+          height: 30px;
+          line-height: 30px;
+          background-image: linear-gradient(90deg, #ff8a00 0, #ff5a00 100%), linear-gradient(#ff7800, #ff7800);
+          background-blend-mode: normal, normal;
+          border-radius: 14px;
+          border: solid 1px #e5e5e5;
+          color: #fff;
+        }
+      }
+    }
+  }
+  .list:hover {
+    box-shadow: 0 0 5px 0 $global-color-107;
+    .name {
+      background-color: $global-color-107;
+      color: $global-color-fff;
+    }
+  }
+  .page {
+    margin: 10px 0;
+    display: flex;
+    justify-content: center;
+  }
+}
+</style>

+ 203 - 3
src/views/two/add/demand.vue

@@ -29,10 +29,47 @@
         </custom-form>
         </custom-form>
       </el-col>
       </el-col>
     </el-row>
     </el-row>
+    <el-dialog v-model="dialog.show" :title="dialog.title" :destroy-on-close="false" @close="toClose" :width="width">
+      <el-row>
+        <transition name="why">
+          <el-col :span="24" v-if="dialog.type == '2'" class="dialog" v-loading="isLoading" element-loading-text="智能推荐中..." :element-loading-svg="svg" element-loading-svg-view-box="-10,-10,50,50">
+            <el-empty v-if="supplytotal == 0" description="暂无数据" />
+            <div class="list" v-for="(item, index) in supplyList" :key="index" @click="toView(item)">
+              <h2 class="name textMore">
+                <span>{{ item.name || '暂无' }}</span>
+              </h2>
+              <div class="other">
+                <span class="other_1">{{ getDict(item.urgent, 'urgent') || '暂无' }}</span>
+                <div class="other_2">
+                  <span>应用行业:</span>
+                  {{ item.field || '暂无' }}
+                </div>
+                <div class="other_2">
+                  <span>所属产业:</span>
+                  {{ item.industry || '暂无' }}
+                </div>
+                <div class="other_2">
+                  <span>来源:</span>
+                  {{ item.source || '暂无' }}
+                </div>
+                <div class="other_2">
+                  <span>推荐指数:</span>
+                  <el-rate size="large" v-model="item._recommend" disabled show-score text-color="#ff9900" :score-template="`${item._recommend} 星`" />
+                </div>
+              </div>
+            </div>
+            <el-col :span="24" class="page">
+              <el-pagination background layout="prev, pager, next" :total="supplytotal" :page-size="supplylimit" v-model:current-page="scurrentPage" @current-change="schangePage" @size-change="ssizeChange" />
+            </el-col>
+          </el-col>
+        </transition>
+      </el-row>
+    </el-dialog>
   </div>
   </div>
 </template>
 </template>
 
 
 <script setup>
 <script setup>
+const router = useRouter()
 import { cloneDeep, get } from 'lodash-es'
 import { cloneDeep, get } from 'lodash-es'
 const $checkRes = inject('$checkRes')
 const $checkRes = inject('$checkRes')
 import { UserStore } from '@/store/user'
 import { UserStore } from '@/store/user'
@@ -44,6 +81,8 @@ import { DictDataStore } from '@/store/api/system/dictData'
 import { TagsStore } from '@/store/api/system/tags'
 import { TagsStore } from '@/store/api/system/tags'
 import { SectorStore } from '@/store/api/platform/sector'
 import { SectorStore } from '@/store/api/platform/sector'
 import { RegionStore } from '@/store/api/system/region'
 import { RegionStore } from '@/store/api/system/region'
+import { EsStore } from '@/store/api/es'
+const esStore = EsStore()
 const regionStore = RegionStore()
 const regionStore = RegionStore()
 const store = DemandStore()
 const store = DemandStore()
 const dictDataStore = DictDataStore()
 const dictDataStore = DictDataStore()
@@ -85,6 +124,26 @@ const formFields = ref([
   { label: '简介', model: 'brief', type: 'textarea' }
   { label: '简介', model: 'brief', type: 'textarea' }
 ])
 ])
 const rules = reactive({ name: [{ required: true, message: '请输入需求名称', trigger: 'blur' }] })
 const rules = reactive({ name: [{ required: true, message: '请输入需求名称', trigger: 'blur' }] })
+
+// 推荐供给列表
+const supplyList = ref([])
+let supplyskip = 0
+let supplylimit = 4
+const supplytotal = ref(0)
+const key = ref('')
+const width = ref('50%')
+const isLoading = ref(false)
+const svg = ref(`
+          <path class="path" d="
+            M 30 15
+            L 28 17
+            M 25.61 25.61
+            A 15 15, 0, 0, 1, 15 30
+            A 15 15, 0, 1, 1, 27.99 7.5
+            L 15 15
+          " style="stroke-width: 4px; fill: rgba(0, 0, 0, 0)"/>
+        `)
+const dialog = ref({ type: '1', show: false, title: '供给智能推荐' })
 // 请求
 // 请求
 onMounted(async () => {
 onMounted(async () => {
   loading.value = true
   loading.value = true
@@ -134,7 +193,11 @@ const toSave = async () => {
   else res = await store.create({ ...data, ...other })
   else res = await store.create({ ...data, ...other })
   if ($checkRes(res, true)) {
   if ($checkRes(res, true)) {
     ElMessage({ message: `发布成功可以长历史发布查看`, type: 'success' })
     ElMessage({ message: `发布成功可以长历史发布查看`, type: 'success' })
-    form.value = {}
+    key.value = form.value.name
+    await toClose()
+    await searchSupply({ supplyskip, supplylimit })
+    width.value = '90%'
+    dialog.value = { type: '2', show: true, title: '相关供给推荐' }
   }
   }
 }
 }
 const toDraftSave = async () => {
 const toDraftSave = async () => {
@@ -150,8 +213,145 @@ const toDraftSave = async () => {
   else res = await store.create({ ...data, ...other })
   else res = await store.create({ ...data, ...other })
   if ($checkRes(res, true)) {
   if ($checkRes(res, true)) {
     ElMessage({ message: `发布成功可以长历史发布查看`, type: 'success' })
     ElMessage({ message: `发布成功可以长历史发布查看`, type: 'success' })
-    form.value = {}
+    key.value = form.value.name
+    await toClose()
+    await searchSupply({ supplyskip, supplylimit })
+    width.value = '90%'
+    dialog.value = { type: '2', show: true, title: '相关供给推荐' }
+  }
+}
+// 供给列表查询
+const searchSupply = async (query = { supplyskip, supplylimit }) => {
+  supplyskip = query.supplyskip
+  supplylimit = query.supplylimit
+  isLoading.value = true
+  const info = { skip: supplyskip, limit: supplylimit, keyword: key.value }
+  const res = await esStore.supply(info)
+  if (res.errcode == '0') {
+    supplyList.value = res.data
+    supplytotal.value = res.total
   }
   }
+  setTimeout(() => {
+    isLoading.value = false
+  }, 3000) // 假设3秒后加载完成
+}
+const scurrentPage = ref(1)
+// 分页
+const schangePage = (page = scurrentPage.value) => {
+  searchSupply({ supplyskip: (page - 1) * supplylimit, supplylimit: supplylimit })
+}
+const ssizeChange = (limits) => {
+  supplylimit = limits
+  scurrentPage.value = 1
+  searchSupply({ supplyskip: 0, supplylimit: supplylimit })
+}
+// 字典数据转换
+const getDict = (data, model) => {
+  if (data) {
+    let res
+    if (model == 'status') res = statusList.value.find((f) => f.value == data)
+    else if (model == 'urgent') res = urgentList.value.find((f) => f.value == data)
+    return get(res, 'label')
+  }
+}
+// 查看详情
+const toView = (item) => {
+  router.push({ path: '/supply/detail', query: { id: item.id || item._id } })
+}
+const toClose = () => {
+  form.value = {}
+  width.value = '50%'
+  dialog.value = { show: false }
 }
 }
 </script>
 </script>
-<style scoped lang="scss"></style>
+<style scoped lang="scss">
+.why-enter-from,
+.why-leave-to {
+  opacity: 0;
+  transform: scale(0.6);
+}
+
+.why-enter-to,
+.why-leave-from {
+  opacity: 1;
+  transform: scale(1);
+}
+
+.why-enter-active,
+.why-leave-active {
+  transition: all 2s ease;
+}
+.dialog {
+  display: flex;
+  flex-wrap: wrap;
+  margin-top: 20px;
+  .list {
+    position: relative;
+    margin-right: 10px;
+    margin-bottom: 10px;
+    width: 380px;
+    box-shadow: 0 0 13px 0 rgba(5, 88, 219, 0.18);
+    .name {
+      padding: 10px 20px;
+      width: 380px;
+      height: 71px;
+      background-color: #dce5ff;
+      font-size: 16px;
+      line-height: 24px;
+      color: #0d0d0d;
+      display: flex;
+      align-items: center;
+    }
+    .other {
+      padding: 10px 20px 20px;
+      .other_1 {
+        padding: 0 10px;
+        height: 25px;
+        background-color: #e6f2fd;
+        border-radius: 2px;
+        border: solid 1px #cae0f5;
+        font-size: $global-font-size-14;
+        line-height: 25px;
+        color: #0085f5;
+      }
+      .other_2 {
+        display: flex;
+        justify-content: space-between;
+        align-items: center;
+        margin-top: 15px;
+        font-size: $global-font-size-16;
+        span {
+          color: #909090;
+        }
+        .state {
+          position: absolute;
+          right: 20px;
+          bottom: 15px;
+          display: inline-block;
+          vertical-align: middle;
+          padding: 0 20px;
+          height: 30px;
+          line-height: 30px;
+          background-image: linear-gradient(90deg, #ff8a00 0, #ff5a00 100%), linear-gradient(#ff7800, #ff7800);
+          background-blend-mode: normal, normal;
+          border-radius: 14px;
+          border: solid 1px #e5e5e5;
+          color: #fff;
+        }
+      }
+    }
+  }
+  .list:hover {
+    box-shadow: 0 0 5px 0 $global-color-107;
+    .name {
+      background-color: $global-color-107;
+      color: $global-color-fff;
+    }
+  }
+  .page {
+    margin: 10px 0;
+    display: flex;
+    justify-content: center;
+  }
+}
+</style>

+ 209 - 3
src/views/two/add/supply.vue

@@ -29,10 +29,48 @@
         </custom-form>
         </custom-form>
       </el-col>
       </el-col>
     </el-row>
     </el-row>
+    <el-dialog v-model="dialog.show" :title="dialog.title" :destroy-on-close="false" @close="toClose" :width="width">
+      <el-row>
+        <transition name="why">
+          <el-col :span="24" v-if="dialog.type == '2'" class="dialog" v-loading="isLoading" element-loading-text="智能推荐中..." :element-loading-svg="svg" element-loading-svg-view-box="-10,-10,50,50">
+            <el-empty v-if="demandtotal == 0" description="暂无数据" />
+            <div class="list" v-for="(item, index) in demandList" :key="index" @click="toView(item)">
+              <h2 class="name textMore">
+                <span>{{ item.name || '暂无' }}</span>
+              </h2>
+              <div class="other">
+                <span class="other_1">{{ getDict(item.urgent, 'urgent') || '暂无' }}</span>
+                <div class="other_2">
+                  <span>应用行业:</span>
+                  {{ item.field || '暂无' }}
+                </div>
+                <div class="other_2">
+                  <span>资金预算:</span>
+                  {{ item.money || '面议' }}
+                </div>
+                <div class="other_2">
+                  <span>推荐指数:</span>
+                  <el-rate size="large" v-model="item._recommend" disabled show-score text-color="#ff9900" :score-template="`${item._recommend} 星`" />
+                </div>
+                <div class="other_2 textOne">
+                  <el-icon color="#0085f5"><Location /></el-icon>
+                  {{ getArea(item.area) }}
+                  <span class="state">{{ getDict(item.status, 'status') || '未解决' }}</span>
+                </div>
+              </div>
+            </div>
+            <el-col :span="24" class="page">
+              <el-pagination background layout="prev, pager, next" :total="demandtotal" :page-size="demandlimit" v-model:current-page="dcurrentPage" @current-change="dchangePage" @size-change="dsizeChange" />
+            </el-col>
+          </el-col>
+        </transition>
+      </el-row>
+    </el-dialog>
   </div>
   </div>
 </template>
 </template>
 
 
 <script setup>
 <script setup>
+const router = useRouter()
 import { cloneDeep, get } from 'lodash-es'
 import { cloneDeep, get } from 'lodash-es'
 const $checkRes = inject('$checkRes')
 const $checkRes = inject('$checkRes')
 import { UserStore } from '@/store/user'
 import { UserStore } from '@/store/user'
@@ -44,6 +82,8 @@ import { DictDataStore } from '@/store/api/system/dictData'
 import { TagsStore } from '@/store/api/system/tags'
 import { TagsStore } from '@/store/api/system/tags'
 import { SectorStore } from '@/store/api/platform/sector'
 import { SectorStore } from '@/store/api/platform/sector'
 import { RegionStore } from '@/store/api/system/region'
 import { RegionStore } from '@/store/api/system/region'
+import { EsStore } from '@/store/api/es'
+const esStore = EsStore()
 const regionStore = RegionStore()
 const regionStore = RegionStore()
 const store = SupplyStore()
 const store = SupplyStore()
 const dictDataStore = DictDataStore()
 const dictDataStore = DictDataStore()
@@ -78,6 +118,26 @@ const formFields = ref([
   { label: '简介', model: 'brief', type: 'textarea' }
   { label: '简介', model: 'brief', type: 'textarea' }
 ])
 ])
 const rules = reactive({ name: [{ required: true, message: '请输入供给名称', trigger: 'blur' }] })
 const rules = reactive({ name: [{ required: true, message: '请输入供给名称', trigger: 'blur' }] })
+// 加载中
+const isLoading = ref(false)
+const svg = ref(`
+          <path class="path" d="
+            M 30 15
+            L 28 17
+            M 25.61 25.61
+            A 15 15, 0, 0, 1, 15 30
+            A 15 15, 0, 1, 1, 27.99 7.5
+            L 15 15
+          " style="stroke-width: 4px; fill: rgba(0, 0, 0, 0)"/>
+        `)
+// 推荐需求列表
+const demandList = ref([])
+let demandskip = 0
+let demandlimit = 4
+const demandtotal = ref(0)
+const key = ref('')
+const width = ref('50%')
+const dialog = ref({ type: '1', show: false, title: '需求智能推荐' })
 // 请求
 // 请求
 onMounted(async () => {
 onMounted(async () => {
   loading.value = true
   loading.value = true
@@ -127,7 +187,11 @@ const toSave = async () => {
   else res = await store.create({ ...data, ...other })
   else res = await store.create({ ...data, ...other })
   if ($checkRes(res, true)) {
   if ($checkRes(res, true)) {
     ElMessage({ message: `发布成功可以长历史发布查看`, type: 'success' })
     ElMessage({ message: `发布成功可以长历史发布查看`, type: 'success' })
-    form.value = {}
+    key.value = form.value.name
+    await toClose()
+    await searchDemand({ demandskip, demandlimit })
+    width.value = '90%'
+    dialog.value = { type: '2', show: true, title: '相关需求推荐' }
   }
   }
 }
 }
 const toDraftSave = async () => {
 const toDraftSave = async () => {
@@ -143,8 +207,150 @@ const toDraftSave = async () => {
   else res = await store.create({ ...data, ...other })
   else res = await store.create({ ...data, ...other })
   if ($checkRes(res, true)) {
   if ($checkRes(res, true)) {
     ElMessage({ message: `发布成功可以长历史发布查看`, type: 'success' })
     ElMessage({ message: `发布成功可以长历史发布查看`, type: 'success' })
-    form.value = {}
+    key.value = form.value.name
+    await toClose()
+    await searchDemand({ demandskip, demandlimit })
+    width.value = '90%'
+    dialog.value = { type: '2', show: true, title: '相关需求推荐' }
+  }
+}
+const toClose = () => {
+  form.value = {}
+  width.value = '50%'
+  dialog.value = { show: false }
+}
+// 地区
+const getArea = (data) => {
+  if (data) return data.join('-')
+  else return '暂无地区'
+}
+// 字典数据转换
+const getDict = (data, model) => {
+  if (data) {
+    let res
+    if (model == 'status') res = statusList.value.find((f) => f.value == data)
+    else if (model == 'urgent') res = urgentList.value.find((f) => f.value == data)
+    return get(res, 'label')
   }
   }
 }
 }
+// 需求列表查询
+const searchDemand = async (query = { demandskip, demandlimit }) => {
+  demandskip = query.demandskip
+  demandlimit = query.demandlimit
+  isLoading.value = true
+  const info = { skip: demandskip, limit: demandlimit, keyword: key.value }
+  const res = await esStore.demand(info)
+  if (res.errcode == '0') {
+    demandList.value = res.data
+    demandtotal.value = res.total
+  }
+  setTimeout(() => {
+    isLoading.value = false
+  }, 3000) // 假设3秒后加载完成
+}
+// 查看详情
+const toView = (item) => {
+  router.push({ path: '/demand/detail', query: { id: item.id || item._id } })
+}
+const dcurrentPage = ref(1)
+// 分页
+const dchangePage = (page = dcurrentPage.value) => {
+  searchDemand({ demandskip: (page - 1) * demandlimit, demandlimit: demandlimit })
+}
+const dsizeChange = (limits) => {
+  demandlimit = limits
+  dcurrentPage.value = 1
+  searchDemand({ demandskip: 0, demandlimit: demandlimit })
+}
 </script>
 </script>
-<style scoped lang="scss"></style>
+<style scoped lang="scss">
+.why-enter-from,
+.why-leave-to {
+  opacity: 0;
+  transform: scale(0.6);
+}
+
+.why-enter-to,
+.why-leave-from {
+  opacity: 1;
+  transform: scale(1);
+}
+
+.why-enter-active,
+.why-leave-active {
+  transition: all 2s ease;
+}
+.dialog {
+  display: flex;
+  justify-content: space-between;
+  flex-wrap: wrap;
+  margin-top: 20px;
+  .list {
+    position: relative;
+    margin-right: 10px;
+    margin-bottom: 10px;
+    width: 380px;
+    box-shadow: 0 0 13px 0 rgba(5, 88, 219, 0.18);
+    .name {
+      padding: 10px 20px;
+      width: 380px;
+      height: 71px;
+      background-color: #dce5ff;
+      font-size: 16px;
+      line-height: 24px;
+      color: #0d0d0d;
+      display: flex;
+      align-items: center;
+    }
+    .other {
+      padding: 10px 20px 20px;
+      .other_1 {
+        padding: 0 10px;
+        height: 25px;
+        background-color: #e6f2fd;
+        border-radius: 2px;
+        border: solid 1px #cae0f5;
+        font-size: $global-font-size-14;
+        line-height: 25px;
+        color: #0085f5;
+      }
+      .other_2 {
+        display: flex;
+        align-items: center;
+        margin-top: 15px;
+        font-size: $global-font-size-16;
+        span {
+          color: #909090;
+        }
+        .state {
+          position: absolute;
+          right: 20px;
+          bottom: 15px;
+          display: inline-block;
+          vertical-align: middle;
+          padding: 0 20px;
+          height: 30px;
+          line-height: 30px;
+          background-image: linear-gradient(90deg, #ff8a00 0, #ff5a00 100%), linear-gradient(#ff7800, #ff7800);
+          background-blend-mode: normal, normal;
+          border-radius: 14px;
+          border: solid 1px #e5e5e5;
+          color: #fff;
+        }
+      }
+    }
+  }
+  .list:hover {
+    box-shadow: 0 0 5px 0 $global-color-107;
+    .name {
+      background-color: $global-color-107;
+      color: $global-color-fff;
+    }
+  }
+  .page {
+    margin: 10px 0;
+    display: flex;
+    justify-content: center;
+  }
+}
+</style>