index.vue 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544
  1. <template>
  2. <custom-layout class="main">
  3. <!-- <div class="loading" v-if="loading">
  4. <el-image class="image" :src="load" fit="fill" />
  5. </div> -->
  6. <div class="w_1700 one">
  7. <div class="left">
  8. <div class="left_1">
  9. <div class="titleOne">
  10. <el-image class="image" :src="left" fit="fill" />
  11. <div class="title_center">供给信息</div>
  12. <el-image class="image" :src="right" fit="fill" />
  13. </div>
  14. <el-empty v-if="supplytotal == 0" description="暂无数据" />
  15. <div class="leftOne" v-else>
  16. <div class="list" v-for="(item, index) in supplyList" :key="index">
  17. <div class="title">
  18. {{ item.name || '暂无供给名称' }}
  19. </div>
  20. <div class="other_1" v-if="user && user.id">
  21. <span>技术领域:</span>
  22. <span class="textOne">{{ item.field || '暂无技术领域' }}</span>
  23. </div>
  24. <div class="other_1" v-if="user && user.id">
  25. <span>所属产业:</span>
  26. <span class="textOne">{{ item.industry || '暂无所属产业' }}</span>
  27. </div>
  28. <div class="other_1" v-if="user && user.id">
  29. <span>来源:</span>
  30. <span class="textOne">{{ item.source || '暂无来源' }}</span>
  31. </div>
  32. <div class="button">
  33. <div @click="toView(item, '0')" class="detail1">查看详情</div>
  34. <div @click="toMate(item, '0')" class="detail2">匹配</div>
  35. </div>
  36. </div>
  37. <el-col :span="24" class="page">
  38. <el-pagination background layout="prev, pager, next" :total="supplytotal" :page-size="supplylimit" v-model:current-page="currentPageone" @current-change="changePageone" @size-change="sizeChangeone" />
  39. </el-col>
  40. </div>
  41. </div>
  42. <div class="left_1">
  43. <div class="titleOne">
  44. <el-image class="image" :src="left" fit="fill" />
  45. <div class="title_center">需求信息</div>
  46. <el-image class="image" :src="right" fit="fill" />
  47. </div>
  48. <el-empty v-if="demandtotal == 0" description="暂无数据" />
  49. <div v-else class="leftOne">
  50. <div class="list" v-for="(item, index) in demandList" :key="index">
  51. <div class="title">
  52. {{ item.name || '暂无需求名称' }}
  53. </div>
  54. <div class="other_1" v-if="user && user.id">
  55. <span>需求企业:</span>
  56. <span class="textOne">{{ item.company || '暂无需求企业' }}</span>
  57. </div>
  58. <div class="other_1" v-if="user && user.id">
  59. <span>技术领域:</span>
  60. <span class="textOne">{{ item.field || '暂无技术领域' }}</span>
  61. </div>
  62. <div class="other_1" v-if="user && user.id">
  63. <span>所在地:</span>
  64. <span class="textOne">{{ getArea(item.area) || '暂无所在地' }}</span>
  65. </div>
  66. <div class="other_1" v-if="user && user.id">
  67. <span>投入预算:</span>
  68. <span class="textOne">{{ item.money || '面议' }}</span>
  69. </div>
  70. <div class="button">
  71. <div @click="toView(item, '1')" class="detail1">查看详情</div>
  72. <div @click="toMate(item, '1')" class="detail2">匹配</div>
  73. </div>
  74. </div>
  75. <el-col :span="24" class="page">
  76. <el-pagination background layout="prev, pager, next" :total="demandtotal" :page-size="demandlimit" v-model:current-page="currentPagetwo" @current-change="changePagetwo" @size-change="sizeChangetwo" />
  77. </el-col>
  78. </div>
  79. </div>
  80. </div>
  81. <div class="center"></div>
  82. <div class="right" v-if="total > 0">
  83. <div class="titleOne">
  84. <el-image class="image" :src="left" fit="fill" />
  85. <div class="title_center">匹配结果</div>
  86. <el-image class="image" :src="right" fit="fill" />
  87. </div>
  88. <div class="rightContent">
  89. <div class="list" v-for="(item, index) in list" :key="index">
  90. <div v-if="item._source == 'achievement'" @click="toView(item, '2')">
  91. <div class="title">
  92. {{ item.name || '暂无成果名称' }}
  93. </div>
  94. <div class="other_1" v-if="user && user.id">
  95. <span>技术领域:</span>
  96. <span class="textOne">{{ item.field || '暂无技术领域' }}</span>
  97. </div>
  98. <div class="other_1" v-if="user && user.id">
  99. <span>负责人:</span>
  100. <span class="textOne">{{ item.person || '暂无负责人' }}</span>
  101. </div>
  102. <div class="other_1" v-if="user && user.id">
  103. <span>所在地:</span>
  104. <span class="textOne">{{ getArea(item.area) || '暂无所在地' }}</span>
  105. </div>
  106. <div class="other_1" v-if="user && user.id">
  107. <span>推荐指数:</span>
  108. <el-rate size="large" v-model="item._recommend" disabled show-score text-color="#ff9900" :score-template="`${item._recommend} 星`" />
  109. </div>
  110. </div>
  111. <div v-if="item._source == 'supply'" @click="toView(item, '0')">
  112. <div class="title">
  113. {{ item.name || '暂无供给名称' }}
  114. </div>
  115. <div class="other_1" v-if="user && user.id">
  116. <span>技术领域:</span>
  117. <span class="textOne">{{ item.field || '暂无技术领域' }}</span>
  118. </div>
  119. <div class="other_1" v-if="user && user.id">
  120. <span>所属产业:</span>
  121. <span class="textOne">{{ item.industry || '暂无所属产业' }}</span>
  122. </div>
  123. <div class="other_1" v-if="user && user.id">
  124. <span>来源:</span>
  125. <span class="textOne">{{ item.source || '暂无来源' }}</span>
  126. </div>
  127. <div class="other_1" v-if="user && user.id">
  128. <span>推荐指数:</span>
  129. <el-rate size="large" v-model="item._recommend" disabled show-score text-color="#ff9900" :score-template="`${item._recommend} 星`" />
  130. </div>
  131. </div>
  132. <div v-if="item._source == 'demand'" @click="toView(item, '1')">
  133. <div class="title">
  134. {{ item.name || '暂无需求名称' }}
  135. </div>
  136. <div class="other_1" v-if="user && user.id">
  137. <span>需求企业:</span>
  138. <span class="textOne">{{ item.company || '暂无需求企业' }}</span>
  139. </div>
  140. <div class="other_1" v-if="user && user.id">
  141. <span>技术领域:</span>
  142. <span class="textOne">{{ item.field || '暂无技术领域' }}</span>
  143. </div>
  144. <div class="other_1" v-if="user && user.id">
  145. <span>所在地:</span>
  146. <span class="textOne">{{ getArea(item.area) || '暂无所在地' }}</span>
  147. </div>
  148. <div class="other_1" v-if="user && user.id">
  149. <span>投入预算:</span>
  150. <span class="textOne">{{ item.money || '面议' }}</span>
  151. </div>
  152. <div class="other_1" v-if="user && user.id">
  153. <span>推荐指数:</span>
  154. <el-rate size="large" v-model="item._recommend" disabled show-score text-color="#ff9900" :score-template="`${item._recommend} 星`" />
  155. </div>
  156. </div>
  157. </div>
  158. </div>
  159. <el-col :span="24" class="page">
  160. <el-pagination background layout="prev, pager, next" :total="total" :page-size="limit" v-model:current-page="currentPage" @current-change="changePage" @size-change="sizeChange" />
  161. </el-col>
  162. </div>
  163. <div class="right" v-else>
  164. <div class="titleOne">
  165. <el-image class="image" :src="left" fit="fill" />
  166. <div class="title_center">匹配结果</div>
  167. <el-image class="image" :src="right" fit="fill" />
  168. </div>
  169. <el-empty description="暂无数据" />
  170. </div>
  171. </div>
  172. </custom-layout>
  173. </template>
  174. <script setup>
  175. import { onBeforeRouteLeave } from 'vue-router'
  176. // 图片引入
  177. import left from '/images/top-left.png'
  178. import right from '/images/top-right.png'
  179. // import load from '/images/load.gif'
  180. // 接口
  181. import { DemandStore } from '@/store/api/platform/demand'
  182. import { SupplyStore } from '@/store/api/platform/supply'
  183. import { EsStore } from '@/store/api/es'
  184. const demandStore = DemandStore()
  185. const supplyStore = SupplyStore()
  186. const esStore = EsStore()
  187. // 用户信息
  188. import { UserStore } from '@/store/user'
  189. const userStore = UserStore()
  190. const user = computed(() => userStore.user)
  191. // 列表
  192. const supplyList = ref([])
  193. let supplyskip = 0
  194. let supplylimit = 3
  195. const supplytotal = ref(0)
  196. const demandList = ref([])
  197. let demandskip = 0
  198. let demandlimit = 3
  199. const demandtotal = ref(0)
  200. // 加载中
  201. const loading = ref(true)
  202. // 路由
  203. const router = useRouter()
  204. const keyword = ref('')
  205. const keywordId = ref()
  206. // 类型
  207. const dataType = ref('0')
  208. // 匹配结果
  209. const list = ref([])
  210. let skip = 0
  211. let limit = 9
  212. const total = ref(0)
  213. // 请求
  214. onMounted(async () => {
  215. loading.value = true
  216. await searchOther()
  217. await searchsupply({ supplyskip, supplylimit })
  218. await searchdemand({ demandskip, demandlimit })
  219. loading.value = false
  220. })
  221. const searchOther = async () => {}
  222. // 供给信息
  223. const searchsupply = async (query = { supplyskip, supplylimit }) => {
  224. supplyskip = query.supplyskip
  225. supplylimit = query.supplylimit
  226. const info = { skip: query.supplyskip, limit: query.supplylimit, is_use: '0', status: '1', user: user.value.id }
  227. let res = await supplyStore.list(info)
  228. if (res.errcode == '0') {
  229. supplyList.value = res.data
  230. supplytotal.value = res.total
  231. }
  232. if (res.total > 0) await toMate(res.data[0], '0')
  233. }
  234. // 需求信息
  235. const searchdemand = async (query = { demandskip, demandlimit }) => {
  236. demandskip = query.demandskip
  237. demandlimit = query.demandlimit
  238. const info = { skip: query.demandskip, limit: query.demandlimit, is_use: '0', status: '1', user: user.value.id }
  239. let res = await demandStore.list(info)
  240. if (res.errcode == '0') {
  241. demandList.value = res.data
  242. demandtotal.value = res.total
  243. }
  244. }
  245. // 转换地区
  246. const getArea = (data) => {
  247. if (data) return data.join('-')
  248. else return '暂无'
  249. }
  250. // 查看详情
  251. const toView = (item, type) => {
  252. if (user.value.id) {
  253. if (type == '0') router.push({ path: '/supply/detail', query: { id: item.id || item._id } })
  254. else if (type == '1') router.push({ path: '/demand/detail', query: { id: item.id || item._id } })
  255. else router.push({ path: '/achievement/detail', query: { id: item.id || item._id } })
  256. } else ElMessage({ message: '未登录!', type: 'error' })
  257. }
  258. const toMate = async (item) => {
  259. loading.value = true
  260. let res
  261. keyword.value = item.name
  262. keywordId.value = item.id
  263. const query = { skip: skip, limit: limit, keyword: item.name, id: item.id }
  264. if (dataType.value != '0') res = await esStore.supply(query)
  265. else res = await esStore.demand(query)
  266. if (res.errcode == '0') {
  267. list.value = res.data
  268. total.value = res.total
  269. }
  270. loading.value = false
  271. }
  272. const currentPageone = ref(1)
  273. const currentPagetwo = ref(1)
  274. // 分页
  275. const changePageone = (page = currentPageone.value) => {
  276. searchsupply({ supplyskip: (page - 1) * supplylimit, supplylimit: supplylimit })
  277. }
  278. const sizeChangeone = (limits) => {
  279. supplylimit = limits
  280. currentPageone.value = 1
  281. searchsupply({ supplyskip: 0, supplylimit: supplylimit })
  282. }
  283. // 分页
  284. const changePagetwo = (page = currentPagetwo.value) => {
  285. searchdemand({ demandskip: (page - 1) * demandlimit, demandlimit: demandlimit })
  286. }
  287. const sizeChangetwo = (limits) => {
  288. demandlimit = limits
  289. currentPagetwo.value = 1
  290. searchdemand({ demandskip: 0, demandlimit: demandlimit })
  291. }
  292. // 匹配结果
  293. const search = async (query = { skip, limit }) => {
  294. skip = query.skip
  295. limit = query.limit
  296. const info = { skip: query.skip, limit: query.limit, keyword: keyword.value, id: keywordId.value }
  297. let res
  298. if (dataType.value != '0') res = await esStore.supply(info)
  299. else res = await esStore.demand(info)
  300. if (res.errcode == '0') {
  301. list.value = res.data
  302. total.value = res.total
  303. }
  304. }
  305. const currentPage = ref(1)
  306. // 分页
  307. const changePage = (page = currentPage.value) => {
  308. search({ skip: (page - 1) * limit, limit: limit })
  309. }
  310. const sizeChange = (limits) => {
  311. limit = limits
  312. currentPage.value = 1
  313. search({ skip: 0, limit: limit })
  314. }
  315. const scrollTop = ref(0)
  316. onActivated(() => {
  317. // 配置参数依赖于浏览器
  318. document.documentElement.scrollTop = scrollTop.value
  319. })
  320. onBeforeRouteLeave((to, from, next) => {
  321. scrollTop.value = document.documentElement.scrollTop || document.body.scrollTop
  322. next()
  323. })
  324. </script>
  325. <style scoped lang="scss">
  326. .main {
  327. .loading {
  328. width: 100%;
  329. height: 70vh;
  330. display: flex;
  331. align-items: center;
  332. justify-content: center;
  333. background-color: #5f5ff5;
  334. .image {
  335. height: 100%;
  336. }
  337. }
  338. .one {
  339. display: flex;
  340. .left {
  341. width: 50%;
  342. .left_1 {
  343. margin: 10px 0;
  344. padding: 20px 0;
  345. box-shadow: 0px 1px 9px 0px rgba(50, 122, 244, 0.12);
  346. .titleOne {
  347. display: flex;
  348. align-items: end;
  349. justify-content: center;
  350. margin: 0 0 30px 0;
  351. .image {
  352. margin: 0 10px;
  353. vertical-align: middle;
  354. border-style: none;
  355. }
  356. .title_center {
  357. font-size: $global-font-size-28;
  358. font-weight: 600;
  359. }
  360. }
  361. .leftOne {
  362. display: flex;
  363. flex-wrap: wrap;
  364. background-color: #ffffff;
  365. .list {
  366. padding-bottom: 20px;
  367. margin: 0 10px 20px 0;
  368. width: 265px;
  369. font-size: 12px;
  370. color: #666666;
  371. border: 1px solid rgb(230, 230, 230);
  372. .title {
  373. color: #002147;
  374. background-color: #c8e0fc;
  375. width: 100%;
  376. height: 36px;
  377. text-align: center;
  378. line-height: 36px;
  379. font-family: PingFangSC-Medium;
  380. font-size: 20px;
  381. font-weight: 500;
  382. overflow: hidden;
  383. text-overflow: ellipsis;
  384. display: -webkit-box;
  385. -webkit-line-clamp: 1;
  386. -webkit-box-orient: vertical;
  387. margin-bottom: 16px;
  388. }
  389. .other_1 {
  390. margin-bottom: 16px;
  391. padding: 0 20px;
  392. display: flex;
  393. color: #666666;
  394. font-size: 16px;
  395. span:first-child {
  396. max-width: 80px;
  397. }
  398. span:last-child {
  399. max-width: 140px;
  400. }
  401. }
  402. .button {
  403. display: flex;
  404. margin: 30px 0 0 0;
  405. .detail1 {
  406. font-size: 16px;
  407. display: block;
  408. margin: 0 auto;
  409. width: 90px;
  410. text-align: center;
  411. line-height: 28px;
  412. border-radius: 28px;
  413. color: #2281ee;
  414. border: 1px solid #2281ee;
  415. cursor: default;
  416. }
  417. .detail2 {
  418. font-size: 16px;
  419. display: block;
  420. margin: 0 auto;
  421. width: 90px;
  422. text-align: center;
  423. line-height: 28px;
  424. border-radius: 28px;
  425. color: #2281ee;
  426. border: 1px solid #2281ee;
  427. cursor: default;
  428. }
  429. .detail1:hover {
  430. color: #fff;
  431. background-color: #2281ee;
  432. }
  433. .detail2:hover {
  434. color: #fff;
  435. background-color: #2281ee;
  436. }
  437. }
  438. }
  439. .list:first-child {
  440. margin: 0 10px 20px 10px;
  441. }
  442. .list:nth-child(3n) {
  443. margin: 0 0 20px 0 !important;
  444. }
  445. }
  446. .page {
  447. display: flex;
  448. justify-content: center;
  449. margin: 20px 0 0 0;
  450. }
  451. }
  452. .left_1:first-child {
  453. margin: 20px 0 20px 0;
  454. }
  455. }
  456. .center {
  457. margin: 10px;
  458. border-left: 3px dashed #e5e5e5;
  459. }
  460. .right {
  461. width: 50%;
  462. .titleOne {
  463. display: flex;
  464. align-items: end;
  465. justify-content: center;
  466. margin: 30px;
  467. .image {
  468. margin: 0 10px;
  469. vertical-align: middle;
  470. border-style: none;
  471. }
  472. .title_center {
  473. font-size: $global-font-size-28;
  474. font-weight: 600;
  475. }
  476. }
  477. .rightContent {
  478. display: flex;
  479. flex-wrap: wrap;
  480. margin: 10px 0;
  481. background-color: $global-color-fff;
  482. .list {
  483. margin: 0 10px 20px 0;
  484. width: 272px;
  485. font-size: 12px;
  486. color: #666666;
  487. border: 1px solid rgb(230, 230, 230);
  488. .title {
  489. color: #002147;
  490. background-color: #c8e0fc;
  491. width: 100%;
  492. height: 36px;
  493. text-align: center;
  494. line-height: 36px;
  495. font-family: PingFangSC-Medium;
  496. font-size: 20px;
  497. font-weight: 500;
  498. overflow: hidden;
  499. text-overflow: ellipsis;
  500. display: -webkit-box;
  501. -webkit-line-clamp: 1;
  502. -webkit-box-orient: vertical;
  503. margin-bottom: 16px;
  504. padding: 0 10px;
  505. cursor: default;
  506. }
  507. .title:hover {
  508. color: #fff;
  509. background-color: #409eff;
  510. }
  511. .other_1 {
  512. margin-bottom: 10px;
  513. padding: 0 20px;
  514. display: flex;
  515. align-items: center;
  516. color: #666666;
  517. font-size: 16px;
  518. span:first-child {
  519. max-width: 80px;
  520. }
  521. span:last-child {
  522. max-width: 148px;
  523. }
  524. }
  525. }
  526. .list:nth-child(3n) {
  527. margin: 0 0 20px 0 !important;
  528. }
  529. }
  530. .page {
  531. display: flex;
  532. justify-content: center;
  533. margin: 10px 0;
  534. }
  535. }
  536. }
  537. }
  538. </style>