找企业

This commit is contained in:
hh
2022-01-20 17:47:46 +08:00
parent 052f18cae4
commit edb9b580cd
13 changed files with 1470 additions and 111 deletions

View File

@ -28,6 +28,7 @@
"nprogress": "0.2.0",
"vue": "3.2.22",
"vue-cropper": "1.0.2",
"vue-fullpage.js": "^0.1.7",
"vue-router": "4.0.12",
"vuex": "4.0.2"
},

View File

@ -39,6 +39,14 @@ export const constantRoutes = [
path: '',
component: () => import('../views/website/index/index.vue'),
},
{
path: 'searchList/0',
component: () => import('../views/website/searchList/index0.vue'),
},
{
path: 'searchList/0/detail/:id',
component: () => import('../views/website/searchList/index0Detail.vue'),
},
{
path: 'solution/:name',
name: 'solution',

View File

@ -5,9 +5,9 @@
<el-col :push="4" :sm="10" :md="12">
<div class="tab">
<div
v-for="(v,index) in queryParams.tabList"
:class="{ active: queryParams.tabIndex == index }"
@click="queryParams.tabIndex = index"
v-for="(v,index) in state.tabList"
:class="{ active: state.tabIndex == index }"
@click="state.tabIndex = index"
>{{ v }}</div>
</div>
</el-col>
@ -15,7 +15,7 @@
<div style="height: 16px;"></div>
<el-row>
<el-col :push="4" :sm="10" :md="12">
<el-input v-model.trim="queryParams.input3" placeholder="请输入检索词">
<el-input v-model.trim="state.keyword" placeholder="请输入检索词">
<template #append>
<el-button class="x_btns" icon="Search" @click="handleQuery">搜索</el-button>
</template>
@ -33,23 +33,23 @@
<el-col :push="3" :pull="3" :span="18">
<div class="numBox">
<div>
<div class="val">9800+</div>
<div class="val">{{ state.data.expert_count }}</div>
<div class="des">专家数量</div>
</div>
<div>
<div class="val">98000+</div>
<div class="val">{{ state.data.patent_count + state.data.achievement_count }}</div>
<div class="des">专利成果数量</div>
</div>
<div>
<div class="val">10000+</div>
<div class="val">{{ state.data.demand_count }}</div>
<div class="des">需求数量</div>
</div>
<div>
<div class="val">120000+</div>
<div class="val">{{ state.data.docking_count }}</div>
<div class="des">对接数量</div>
</div>
<div>
<div class="val">11000+</div>
<div class="val">{{ state.data.company_count }}</div>
<div class="des">实验室数量</div>
</div>
</div>
@ -59,25 +59,49 @@
</div>
</template>
<script setup lang="ts">
<script setup>
import { onMounted, reactive } from "vue";
const queryParams = reactive({
pageNum: 1,
pageSize: 10,
input3: "",
const router = useRouter();
import request from '@/utils/request'
function indexData () {
return request({
url: '/v1/index',
method: 'get',
})
}
function handleDetail (mode, keyword) {
let routeData = router.resolve({ path: `/searchList/${mode}`, query: { keyword } });
window.open(routeData.href, '_blank');
}
function handleQuery () {
console.log(state.keyword, state.tabIndex)
handleDetail(state.tabIndex, state.keyword)
}
const state = reactive({
keyword: "",
tabList: [
'找企业', '找成果', '找实验室', '找专利', '找专家', '接需求'
],
tabIndex: 0,
data: {
expert_count: 0,
company_count: 0,
patent_count: 0,
achievement_count: 0,
demand_count: 0,
docking_count: 0,
}
});
function handleQuery() {
queryParams.pageNum = 1;
getList();
}
function getList() { }
onMounted(() => {
console.log("onmunted");
indexData().then(res => {
if (200 == res.code) {
state.data = res.data
}
})
// console.log("onmunted");
});
</script>

View File

@ -1,5 +1,32 @@
<template>
<div class="home">
<div class="fullPage" ref="fullPage">
<div
class="fullPageContainer"
ref="fullPageContainer"
@mousewheel="mouseWheelHandle"
@DOMMouseScroll="mouseWheelHandle"
>
<div
v-for="(item, $index) in state.boxList"
class="section"
:key="$index"
:style="`z-index: ${item.zIndex};`"
>
<component :is="item.comp"></component>
</div>
<!-- <div class="section"><index1></index1></div>
<div class="section"><index2 /></div>
<div class="section"><index3 /></div>
<div class="section"><index4 /></div>
<div class="section"><index5 /></div>
<div class="section"><index6 /></div>
<div class="section"><index7 /></div>
<div class="section"><index8 /></div>-->
</div>
</div>
<!-- <div class="home">
<transition-group
:enter-active-class="state.animate.in"
:leave-active-class="state.animate.out"
@ -14,12 +41,12 @@
<component :is="item.comp"></component>
</div>
</transition-group>
</div>
</div>-->
</template>
<script setup lang="ts">
import { reactive, onMounted } from "vue";
import { reactive, onMounted, getCurrentInstance } from "vue";
const { proxy } = getCurrentInstance();
import index1 from './comp/index1.vue';
import index2 from './comp/index2.vue';
import index3 from './comp/index3.vue';
@ -29,7 +56,62 @@ import index6 from './comp/index6.vue';
import index7 from './comp/index7.vue';
import index8 from './comp/index8.vue';
function next() { // 往下切换
let len = 8; // 页面的个数
if (state.fullpage.current + 1 <= len) { // 如果当前页面编号+1 小于总个数,则可以执行向下滑动
state.fullpage.current += 1; // 页面+1
move(state.fullpage.current); // 执行切换
}
}
function pre() {// 往上切换
if (state.fullpage.current - 1 > 0) { // 如果当前页面编号-1 大于0则可以执行向下滑动
state.fullpage.current -= 1;// 页面+1
move(state.fullpage.current);// 执行切换
}
}
function move(index) {
state.fullpage.isScrolling = true; // 为了防止滚动多页,需要通过一个变量来控制是否滚动
directToMove(index); //执行滚动
setTimeout(() => { //这里的动画是1s执行完使用setTimeout延迟1s后解锁
state.fullpage.isScrolling = false;
}, 1010);
}
function directToMove(index) {
let height = proxy.$refs["fullPage"]['clientHeight']; //获取屏幕的宽度
let scrollPage = proxy.$refs["fullPageContainer"]; // 获取执行tarnsform的元素
let scrollHeight; // 计算滚动的告诉,是往上滚还往下滚
scrollHeight = -(index - 1) * height + "px";
scrollPage.style.transform = `translateY(${scrollHeight})`;
state.fullpage.current = index;
}
function mouseWheelHandle(event) { // 监听鼠标监听
// 添加冒泡阻止
let evt = event || window.event;
if (evt.stopPropagation) {
evt.stopPropagation();
} else {
evt.returnValue = false;
}
if (state.fullpage.isScrolling) { // 判断是否可以滚动
return false;
}
let e = event.originalEvent || event;
state.fullpage.deltaY = e.deltaY || e.detail; // Firefox使用detail
if (state.fullpage.deltaY > 0) {
next();
} else if (state.fullpage.deltaY < 0) {
pre();
}
}
let state = reactive({
fullpage: {
current: 1, // 当前的页面编号
isScrolling: false, // 是否在滚动,是为了防止滚动多页,需要通过一个变量来控制是否滚动
deltaY: 0 // 返回鼠标滚轮的垂直滚动量保存的鼠标滚动事件的deleteY,用来判断是往下还是往上滚
},
showBox: 0,
boxList: [
{
@ -78,101 +160,27 @@ let state = reactive({
out: "animate__animated animate__fadeOutDown",
},
});
function choice(i: number) {
if (i > state.showBox && i == (state.boxList.length + 1)) return false;
if(i < state.showBox && i == 0) return false;
if (i === state.showBox) return false;
// style 的 z-index 属性提升到最上面
state.boxList.forEach((item, idx) => {
if (idx === i) {
item.zIndex = 100;
} else {
item.zIndex = 1;
}
});
// 根据判断当前显示的 box 下标和点击的下标进行对比,修改动画方向
const animateType = "fade";
if (i > state.showBox) {
state.animate.in = `animate__animated animate__${animateType}InUp`;
state.animate.out = `animate__animated animate__${animateType}OutUp`;
} else {
state.animate.in = `animate__animated animate__${animateType}InDown`;
state.animate.out = `animate__animated animate__${animateType}OutDown`;
}
state.showBox = i;
}
const mouseWheelHandler = (event: any) => {
let i = state.showBox;
if (mouseWheelFlag(event) === "up") {
i = i - 1 < 0 ? state.boxList.length - 1 : i - 1;
} else {
i = i + 1 > state.boxList.length - 1 ? 0 : i + 1;
}
choice(i);
};
/**
* mouseWheelFlag
* @param event window.event
* @returns up | down
*/
const mouseWheelFlag: (event: any) => string = (event: any) => {
let delta = 0;
if (!event) event = window.event;
if (event.wheelDelta) {
//IE、chrome浏览器使用的是wheelDelta并且值为“正负120”
delta = event.wheelDelta / 120;
if ((window as any).opera) delta = -delta; //因为IE、chrome等向下滚动是负值FF是正值为了处理一致性在此取反处理
} else if (event.detail) {
//FF浏览器使用的是detail,其值为“正负3”
delta = -event.detail / 3;
}
return delta > 0 ? "up" : "down";
};
/**
* throttle 节流
* @param func 须要包装的函数
* @param delay 延迟时间单位ms
*/
const throttle: (func: any, delay: number, immediate?: boolean) => any = (
func,
delay = 100
) => {
let flag = false;
return (...args: any) => {
if (!flag) {
flag = true;
setTimeout(() => {
flag = false;
func.call(this, ...args);
}, delay);
}
};
};
onMounted(() => {
window.addEventListener("mousewheel", throttle(mouseWheelHandler, 500), true);
});
</script>
<style lang="scss" scoped>
.box {
height: 100%;
.fullPage {
width: 100%;
backdrop-filter: blur(4rpx);
}
.home {
position: relative;
height: 100%;
overflow: hidden;
width: 100%;
.box {
position: absolute;
}
}
.fullPageContainer {
width: 100%;
height: 100%;
transition: all linear 0.5s;
}
.section {
width: 100%;
height: 100%;
background-position: center center;
background-repeat: no-repeat;
}
</style>

View File

@ -0,0 +1,112 @@
<template>
<div class="collectAndVisit">
<div>{{ visit_count }}游览</div>
<div class="heart_w">
<div class="heart" @click="change()" :class="{ in: state.isCollect }"></div>
<span>{{ state.collect }}</span>
</div>
</div>
</template>
<script setup>
import request from '@/utils/request'
import { reactive } from 'vue';
function launch (id) {
return request({
url: '/v1/user/collect/launch',
method: 'post',
data: { kind: props.kind, object_id: props.object_id, }
})
}
let flag = true;
const props = defineProps({
is_collect: {
type: Boolean,
required: true,
},
collect_count: {
type: Number,
required: true,
},
visit_count: {
type: Number,
required: true,
},
kind: {
type: Number,
required: true,
},
object_id: {
type: String,
required: true,
},
});
const state = reactive({
collect: props.collect_count,
isCollect: props.is_collect,
})
async function postData () {
if (flag) {
flag = false;
await launch().then(res => {
if (200 == res.code) {
state.isCollect = res.data;
if (res.data) {
state.collect++;
} else {
state.collect--;
}
}
flag = true;
}).catch(() => {
flag = false;
});
}
}
function change () {
postData();
}
</script>
<style lang="scss" scoped>
.collectAndVisit {
display: flex;
justify-content: space-around;
.heart_w {
vertical-align: text-bottom;
span {
vertical-align: text-bottom;
position: relative;
top: 1px;
}
}
.heart {
cursor: pointer;
user-select: none;
vertical-align: text-bottom;
display: inline-block;
width: 18.3px;
height: 16.4px;
margin-right: 5px;
background-size: cover;
background-image: url(./img/heart0.png);
}
.in {
background-image: url(./img/heart1.png);
}
}
</style>

Binary file not shown.

After

Width:  |  Height:  |  Size: 723 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 503 B

View File

@ -0,0 +1,116 @@
<template>
<div>
<el-row type="flex">
<div style="display: inline-block;line-height: 32px;">所属领域</div>
<div style="flex:1">
<el-row :gutter="10" style="margin-bottom: 10px;">
<el-col :span="8">
<el-select
style="width: 100%;"
placeholder="请选择"
v-model="state.id1"
@change="state.id2 = '';change()"
clearable
>
<el-option
v-for="option in state.industryList"
:key="option.id"
:value="option.id"
:label="option.name"
/>
</el-select>
</el-col>
<el-col :span="8">
<el-select
style="width: 100%;"
placeholder="请选择"
v-model="state.id2"
@change="state.id3 = '';change()"
clearable
>
<el-option
v-for="option in searchIndustryData(state.id1)['children']"
:key="option.id"
:value="option.id"
:label="option.name"
/>
</el-select>
</el-col>
<el-col :span="8">
<el-select
style="width: 100%;"
placeholder="请选择"
v-model="state.id3"
@change="change()"
clearable
>
<el-option
v-for="option in searchIndustryData(state.id2)['children']"
:key="option.id"
:value="option.id"
:label="option.name"
/>
</el-select>
</el-col>
</el-row>
</div>
</el-row>
</div>
</template>
<script setup>
import { onMounted } from 'vue';
import { industry } from "@/api/website/home/index";
const state = reactive({
industryList: [],
id1: '',
id2: '',
id3: '',
});
let treeData = [];
const emit = defineEmits();
function change() {
emit("industryChange", {
id1: state.id1,
id2: state.id2,
id3: state.id3,
});
}
function searchIndustryData (code) {
return deepFindTree(code, treeData);
}
function deepFindTree (code, arr) {
let snap = false;
for (let index = 0; index < arr.length; index++) {
const ele = arr[index];
if (code == ele.id) {
snap = ele;
break;
} else if (ele['children'] != null) {
snap = deepFindTree(code, ele['children']);
if (snap) {
break;
}
} else {
snap = false;
}
}
return snap;
}
function init () {
industry().then(res => {
if (200 == res.code) {
state.industryList = res.data;
treeData = res.data;
}
})
}
onMounted(() => {
init();
});
</script>

View File

@ -0,0 +1,126 @@
<template>
<div class="box">
<div class="wrap">
<div class="img">
<!-- <img :src="data.image" alt /> -->
<img src="https://t7.baidu.com/it/u=1951548898,3927145&fm=193&f=GIF" />
</div>
<div class="content">
<div class="tit">{{ data.title }}</div>
<div class="line">
技术成熟度
<span>{{ data.maturity_title }}</span>
</div>
<div class="line">
合作模式
<span>{{ data.cooperation_mode_title }}</span>
</div>
<div class="labelList">
<div v-for="item in data.industrys">{{ item }}</div>
</div>
</div>
<div>
<div class="keywords">
<wordcloud v-if="data.keywords" :data="createdData(data.keywords)"></wordcloud>
</div>
<collectAndVisit :is_collect="data.is_collect" :collect_count="data.collect_count" :visit_count="data.visit_count" :object_id="data.id" :kind="1005"/>
</div>
</div>
</div>
</template>
<script setup>
import wordcloud from './wordcloud.vue'
import collectAndVisit from './collectAndVisit.vue'
const props = defineProps({
data: {
type: Object,
required: true,
},
});
function createdData (arr) {
let l = [];
let snap = JSON.parse(JSON.stringify(arr))
snap.map(e => {
l.push({ name: e, value: 30 })
return { name: e, value: 30 }
})
return l;
}
</script>
<style lang="scss" scoped>
.box {
width: 100%;
height: 190px;
background: #ffffff;
padding: 20px;
box-sizing: border-box;
.wrap {
display: flex;
flex-direction: row;
.img {
width: 200px;
height: 150px;
margin-right: 10px;
img {
display: block;
margin: 0;
width: 100%;
height: 100%;
}
}
.keywords {
width: 129px;
height: 129px;
}
.content {
flex: 1;
overflow: hidden;
.labelList {
overflow: hidden;
div {
padding: 2px 4px;
float: left;
background: #0054ff;
border-radius: 4px;
margin-right: 5px;
margin-bottom: 5px;
font-size: 14px;
font-family: Source Han Sans CN;
font-weight: 400;
color: #ffffff;
}
}
.line {
font-size: 16px;
font-family: Source Han Sans CN;
font-weight: 400;
color: #666666;
margin: 10px 0;
span {
font-size: 16px;
font-family: Source Han Sans CN;
font-weight: 500;
color: #333;
}
}
.tit {
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
width: 100%;
font-size: 20px;
font-family: Source Han Sans CN;
font-weight: bold;
color: #333333;
overflow: hidden;
}
}
}
}
</style>

View File

@ -0,0 +1,112 @@
<template>
<div class="searchContainer" v-loading="loading">
<div class="wrap">
<div
class="banner"
style="height: 394px;background-size: cover;background-color: #ccc"
:style="{ backgroundImage: state.banner ? `url(${state.banner})` : '' }"
>
<div class="conter1000">
<div class="tit">{{ title }}</div>
<el-input v-model.trim="state.currentKeyword" placeholder="请输入检索词">
<template #append>
<el-button icon="Search" @click="handleQuery">搜索</el-button>
</template>
</el-input>
</div>
</div>
<div class="conter1000">
<slot ></slot>
</div>
</div>
<webFooter></webFooter>
</div>
</template>
<script setup>
import webFooter from "@/components/webFooter/index.vue";
import request from '@/utils/request'
const router = useRouter();
const route = useRoute();
import { banner } from "@/api/website/home/index";
const loading = ref(true);
const state = reactive({
currentKeyword: ''
});
const props = defineProps({
title: {
type: String,
required: true,
},
bannerKey: {
required: true,
type: String,
default: '',
},
});
const emit = defineEmits();
function handleQuery () {
emit("handleQuery", state.currentKeyword);
}
onMounted(() => {
state.currentKeyword = route.query.keyword;
handleQuery();
banner(props.bannerKey).then(res => {
if (200 == res.code) {
state.banner = res.data.images
loading.value = false;
}
}).catch(() => {
loading.value = false;
})
});
</script>
<style lang="scss" scoped>
.searchContainer {
width: 100%;
min-height: 100%;
display: flex;
flex-direction: column;
.wrap {
flex: 1;
background: #F2F6FF;
}
.banner {
display: flex;
align-items: center;
justify-content: center;
.tit {
text-align: center;
font-size: 34px;
line-height: 80px;
font-family: Source Han Sans CN;
font-weight: bold;
color: #ffffff;
text-shadow: 0px 0px 5px rgba(0, 0, 0, 0.2);
}
.el-input {
::v-deep(.el-input__inner) {
border-right: 0;
}
::v-deep(.el-input-group__append) {
overflow: hidden;
font-size: 16px;
color: #fff;
border-top-color: #0054ff;
border-right-color: #0054ff;
border-bottom-color: #0054ff;
background-color: #0054ff;
}
}
::v-deep(.el-input__inner),
::v-deep(.el-input-group__append) {
height: 50px !important;
border-radius: 0;
}
}
}
</style>

View File

@ -0,0 +1,209 @@
<template>
<div class="wordcloud">
<div
class="wordCloud__tagBall"
:style="{width:`${this.width}px`,height:`${this.height}px`}"
@mouseenter="stop"
@mouseleave="start"
>
<span
class="wordCloud__tag"
v-for="(item, index) of data"
:key="index"
:style="{color:color[index % color.length],...contentEle[index].style}"
:title="item.name+item.value"
>{{item.name}}</span>
</div>
</div>
</template>
<script>
export default {
name: 'cloudWork',
props: {
width: {
type: Number,
default: 129
},
height: {
type: Number,
default: 129
},
// 测试数据
data: {
type: Array,
default: () => [
{
name: '测试一类',
value: 30
},
{
name: '测试二类',
value: 30
},
{
name: '测试三类',
value: 30
},
{
name: '测试四类',
value: 30
},
]
}
},
data: () => ({
color: ['#0054FF', '#B9B9B9', '#D1AF07', '#E27914', '#CB4A4D', '#B02690'],
contentEle: [],
direction: '-1',
speed: 400,
animateID: null
}),
created() {
this.contentEle = this.data.map(() => ({
x: 0,
y: 0,
z: 0,
style: {}
}));
},
mounted() {
this.innit();
},
methods: {
innit() {
const RADIUSX = (this.width - 50) / 2;
const RADIUSY = (this.height - 50) / 2;
this.contentEle = [];
for (let i = 0; i < this.data.length; i += 1) {
const k = -1 + (2 * (i + 1) - 1) / this.data.length;
const a = Math.acos(k);
const b = a * Math.sqrt(this.data.length * Math.PI);
const x = RADIUSX * Math.sin(a) * Math.cos(b);
const y = RADIUSY * Math.sin(a) * Math.sin(b);
const z = RADIUSX * Math.cos(a);
const singleEle = {
x,
y,
z,
style: {}
};
this.contentEle.push(singleEle);
}
this.animate();
},
animate() {
this.rotateX();
this.rotateY();
this.move();
this.animateID = window.requestAnimationFrame(this.animate);
},
rotateX() {
const angleX = ['-1', '1'].includes(this.direction)
? Math.PI / Infinity
: Math.PI / ((Number(this.direction) / 2) * Number(this.speed));
const cos = Math.cos(angleX);
const sin = Math.sin(angleX);
this.contentEle = this.contentEle.map((t) => {
const y1 = t.y * cos - t.z * sin;
const z1 = t.z * cos + t.y * sin;
return {
...t,
y: y1,
z: z1
};
});
},
rotateY() {
const angleY = ['-2', '2'].includes(this.direction)
? Math.PI / Infinity
: Math.PI / (Number(this.direction) * Number(this.speed));
const cos = Math.cos(angleY);
const sin = Math.sin(angleY);
this.contentEle = this.contentEle.map((t) => {
const x1 = t.x * cos - t.z * sin;
const z1 = t.z * cos + t.x * sin;
return {
...t,
x: x1,
z: z1
};
});
},
move() {
const CX = this.width / 2;
const CY = this.height / 2;
this.contentEle = this.contentEle.map((singleEle) => {
const { x, y, z } = singleEle;
const fallLength = 500;
const RADIUS = (this.width - 50) / 2;
const scale = fallLength / (fallLength - z);
const alpha = (z + RADIUS) / (2 * RADIUS);
const left = `${x + CX - 15}px`;
const top = `${y + CY - 15}px`;
const transform = `translate(${left}, ${top}) scale(${scale})`;
const style = {
...singleEle.style,
opacity: alpha + 0.5,
zIndex: parseInt(scale * 100, 10),
transform
};
return {
x,
y,
z,
style
};
});
},
// 鼠标移入暂停
stop() {
window.cancelAnimationFrame(this.animateID);
},
// 鼠标离开恢复
start() {
this.animate();
}
}
};
</script>
<style scoped>
button {
margin: 20px;
}
.wordcloud {
width: 100%;
height: 100%;
overflow: hidden;
}
.wordCloud__tagBall {
width: 100%;
height: 100%;
position: relative;
}
.wordCloud__tag {
display: block;
position: absolute;
left: 0px;
top: 0px;
color: green;
text-decoration: none;
font-size: 12px;
font-family: '微软雅黑';
font-weight: bold;
}
.wordCloud__tag :hover {
color: red;
}
.wordCloud__home {
display: flex;
justify-content: center;
}
</style>

View File

@ -0,0 +1,240 @@
<template>
<div class="index">
<searchContainer bannerKey="首页>企业库" title="企业库" @handleQuery="handleQuery">
<template v-slot>
<el-row type="flex" style="padding: 20px 0;">
<div style="flex: 1">
<div style="position: relative;">
<industrySelect @industryChange="industryChange"></industrySelect>
<div class="total">
共找到
<span>{{ state.total }}</span> 家企业
</div>
<div v-loading="loading">
<div class="item" v-for="item in state.list" :key="item.id">
<el-row type="flex" style="padding: 40px 20px;">
<div class="img">
<!-- <img :src="item.image" alt /> -->
<img src="https://t7.baidu.com/it/u=1951548898,3927145&fm=193&f=GIF" alt />
</div>
<div class="content">
<div class="tit" @click="handleDetail(item.id)">
<div style="float: right;">
<span>匹配度</span>
<el-rate style="display: inline-block" v-model="state.val" disabled></el-rate>
</div>
<div class="text" style="flex: 1">{{ item.name }}</div>
</div>
<div class="line">
企业规模 <span>{{item.kind_title}}</span>
</div>
<div class="line">
核心产品及应用场景 <span>{{item.product}}</span>
</div>
<div class="line">
企业网站 <a :href="item.url"><span>{{item.url}}</span></a>
</div>
</div>
<div class="keywords" style="flex: 1">
<wordcloud :data="createdData(item.keywords)"></wordcloud>
</div>
</el-row>
</div>
</div>
<pagination
class="pagination"
:total="state.total"
:pageSizes="state.pageSizes"
v-model:page="state.pageNum"
v-model:limit="state.pageSize"
:autoScroll="false"
@pagination="getDataList"
/>
</div>
</div>
<div class="r">1</div>
</el-row>
</template>
</searchContainer>
</div>
</template>
<script setup>
import request from '@/utils/request'
const router = useRouter();
import { onMounted } from 'vue';
import searchContainer from './components/searchContainer.vue'
import industrySelect from './components/industrySelect.vue'
import wordcloud from './components/wordcloud.vue'
function handleDetail (id) {
let routeData = router.resolve({ path: `/searchList/0/detail/${id}`, query: {keyword: state.keyword}});
window.open(routeData.href, '_blank');
}
const loading = ref(true);
const state = reactive({
pageNum: 1,
total: 1,
pageSize: 10,
pageSizes: [10, 10 << 1, 10 << 2, 10 << 3],
keyword: '',
industryList: [],
id1: '',
id2: '',
id3: '',
val: 3,
arr: [{
"name": "Cat",
"value": 26
},
{
"name": "fish",
"value": 19
}]
});
function createdData(arr) {
let l = [];
let snap = JSON.parse(JSON.stringify(arr))
snap.map(e=>{
l.push({name: e,value: 30})
return {name: e,value: 30}
})
return l;
}
function search () {
let industry = '';
if (state.id1) {
industry += state.id1;
}
if (state.id2) {
industry += `-${state.id2}`;
}
if (state.id3) {
industry += `-${state.id3}`;
}
return request({
url: '/v1/search',
method: 'post',
data: { industry, mode: 1, page_num: state.pageNum, page_size: state.pageSize, keyword: state.keyword }
})
}
function handleQuery (keyword) {
state.keyword = keyword;
getDataList()
}
function industryChange (industry) {
if (industry.id1) {
state.id1 = industry.id1;
}
if (industry.id2) {
state.id2 = industry.id2;
}
if (industry.id3) {
state.id3 = industry.id3;
}
getDataList()
}
function getDataList () {
loading.value = true;
search().then(res => {
if (200 == res.code) {
// 总条数
state.total = res.data.count;
state.list = res.data.data;
loading.value = false;
}
}).catch(() => {
loading.value = false;
})
}
</script>
<style lang="scss" scoped>
.total {
font-size: 16px;
font-family: Source Han Sans CN;
font-weight: 500;
color: #333333;
margin-bottom: 20px;
span {
font-size: 30px;
color: #0054ff;
}
}
.r {
display: inline-block;
width: 325px;
margin-left: 14px;
min-height: 200px;
background-color: #fff;
}
.item {
height: 200px;
overflow: hidden;
background-color: #fff;
margin-bottom: 16px;
.img {
width: 90px;
margin-right: 12px;
display: flex;
align-items:center;
justify-content:center;
img {
width: 90px;
height: 90px;
border-radius: 50%;
}
}
.content {
display: inline-block;
width: 390px;
.line {
font-size: 16px;
font-family: Source Han Sans CN;
font-weight: 400;
color: #666666;
margin: 10px 0;
span {
font-size: 16px;
font-family: Source Han Sans CN;
font-weight: 500;
color: #333;
}
}
}
.keywords {
flex: 1;
width: 129px;
height: 129px;
}
.tit {
width: 100%;
overflow: hidden;
cursor: pointer;
.text {
margin-right: 200px;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
font-size: 20px;
font-family: Source Han Sans CN;
font-weight: bold;
color: #333333;
}
}
}
</style>

View File

@ -0,0 +1,403 @@
<template>
<div v-loading="loading">
<searchContainer bannerKey="首页>企业库" title="企业库" @handleQuery="handleQuery">
<template v-slot>
<div class="head">
<el-breadcrumb separator="/">
<el-breadcrumb-item>
<span class="one">找企业</span>
</el-breadcrumb-item>
<el-breadcrumb-item>
<span>企业详情</span>
</el-breadcrumb-item>
</el-breadcrumb>
</div>
<el-row type="flex">
<div style="flex: 1">
<div class="item">
<el-row type="flex" style="padding: 40px 20px;">
<div class="img">
<!-- <img :src="state.companyDetail.image" alt /> -->
<img
src="https://t7.baidu.com/it/u=1951548898,3927145&fm=193&f=GIF"
alt
/>
</div>
<div class="content">
<div class="tit">
<div style="float: right;">
<span>匹配度</span>
<el-rate
style="display: inline-block"
v-model="state.val"
disabled
></el-rate>
</div>
<div
class="text"
style="flex: 1"
>{{ state.companyDetail.name }}</div>
</div>
<div class="line">
企业规模:
<span>{{ state.companyDetail.introduce }}</span>
</div>
<div class="line">
核心产品及应用场景:
<span>{{ state.companyDetail.product }}</span>
</div>
<div class="line">
企业网站:
<a :href="state.companyDetail.url">
<span>{{ state.companyDetail.url }}</span>
</a>
</div>
</div>
<div class="keywords" style="flex: 1">
<wordcloud
v-if="state.companyDetail.keywords"
:data="createdData(state.companyDetail.keywords)"
></wordcloud>
</div>
<div class="btns">
<div class="order">预约对接</div>
<div class="share">一键分享</div>
</div>
</el-row>
</div>
<div class="product">
<div style="padding: 20px 0;">
<div class="pointTit">企业简介</div>
</div>
<div class="html" v-html="state.companyDetail.introduce"></div>
<div style="padding: 20px 0;">
<div class="pointTit">生产方向</div>
</div>
<section v-if="state.companyDetail.directions">
<div v-for="item in state.companyDetail.directions" class="describe">{{state.companyDetail.introduce}}</div>
</section>
<div style="padding: 20px 0;">
<div class="pointTit">产品列表</div>
</div>
<section v-for="item in state.companyProduct" :key="item.id">
<div style="border: 1px solid #DCDCDC;margin-bottom: 10px;">
<productItem :data="item"></productItem>
</div>
</section>
</div>
<div style="padding: 20px 0;">
<div class="pointTit">企业推荐</div>
</div>
<div>
<div class="item" v-for="item in state.list" :key="item.id">
<el-row type="flex" style="padding: 40px 20px;">
<div class="img">
<!-- <img :src="item.image" alt /> -->
<img
src="https://t7.baidu.com/it/u=1951548898,3927145&fm=193&f=GIF"
alt
/>
</div>
<div class="content">
<div class="tit" @click="handleDetail(item.id)">
<div style="float: right;">
<span>匹配度</span>
<el-rate
style="display: inline-block"
v-model="state.val"
disabled
></el-rate>
</div>
<div
class="text"
style="flex: 1"
>{{ item.name.repeat(10) }}</div>
</div>
<div class="line">
企业规模
<span>{{ item.kind_title }}</span>
</div>
<div class="line">
核心产品及应用场景
<span>{{ item.product }}</span>
</div>
<div class="line">
企业网站
<a :href="item.url">
<span>{{ item.url }}</span>
</a>
</div>
</div>
<div class="keywords" style="flex: 1">
<wordcloud :data="createdData(item.keywords)"></wordcloud>
</div>
</el-row>
</div>
</div>
</div>
<div class="r">1</div>
</el-row>
</template>
</searchContainer>
</div>
</template>
<script setup>
import request from '@/utils/request'
const router = useRouter();
const route = useRoute();
import { onMounted } from 'vue';
import searchContainer from './components/searchContainer.vue'
import wordcloud from './components/wordcloud.vue'
import productItem from './components/productItem.vue'
const loading = ref(true);
const state = reactive({
pageNum: 1,
pageSize: 4,
keyword: '',
val: 3,
companyDetail: {},
companyProduct: [],
arr: [{
"name": "Cat",
"value": 26
},
{
"name": "fish",
"value": 19
}]
});
// 建议 列表前4条
function recommend () {
return request({
url: '/v1/search',
method: 'post',
data: { mode: 1, page_num: state.pageNum, page_size: state.pageSize, keyword: state.keyword }
})
}
// 公司详情
function company (id) {
return request({
url: '/v1/manage/company',
method: 'post',
data: { company_id: id }
})
}
function companyProduct (id) {
return request({
url: '/v1/manage/company/product',
method: 'post',
data: { company_id: id, page_num: 1, page_size: 10, }
})
}
function createdData (arr) {
let l = [];
let snap = JSON.parse(JSON.stringify(arr))
snap.map(e => {
l.push({ name: e, value: 30 })
return { name: e, value: 30 }
})
return l;
}
function handleDetail (id) {
let routeData = router.resolve({ path: `/searchList/0/detail/${id}`, query: { keyword: state.keyword } });
window.open(routeData.href, '_blank');
}
function handleList (mode, keyword) {
router.push({ path: `/searchList/${mode}`, query: { keyword } });
}
// 首次加载数据,其后跳转页面
let flag = true;
function handleQuery (keyword) {
state.keyword = keyword;
if (flag) {
getDataList();
flag = false;
} else {
handleList(0, keyword);
}
}
function getDataList () {
loading.value = true;
recommend().then(res => {
if (200 == res.code) {
// 总条数
state.total = res.data.count;
state.list = res.data.data;
}
})
let id = route.params.id;
if (!id) return
company(id).then(res => {
if (200 == res.code) {
state.companyDetail = res.data;
loading.value = false;
}
}).catch(() => {
loading.value = false;
});
companyProduct(id).then(res => {
if (200 == res.code) {
state.companyProduct = res.data.data;
}
})
}
</script>
<style lang="scss" scoped>
.head {
padding: 15px 0px;
span {
font-size: 16px;
font-family: Source Han Sans CN;
font-weight: 400;
color: #666666;
}
.one {
color: #333333;
}
}
.r {
display: inline-block;
width: 325px;
margin-left: 14px;
min-height: 200px;
background-color: #fff;
}
.product {
width: 661px;
box-sizing: border-box;
padding: 20px;
background: #fff;
.describe {
font-size: 14px;
font-family: Source Han Sans CN;
font-weight: 400;
color: #666666;
margin-bottom: 5px;
}
}
.pointTit {
position: relative;
padding-left: 10px;
font-size: 16px;
font-family: Source Han Sans CN;
font-weight: 500;
color: #333333;
&:before {
content: "";
top: 8px;
left: 0px;
position: absolute;
display: block;
width: 5px;
height: 5px;
background: #0054ff;
}
}
.item {
overflow: hidden;
background-color: #fff;
margin-bottom: 16px;
.btns {
overflow: hidden;
padding-top: 20px;
width: 100%;
div {
text-align: center;
float: right;
cursor: pointer;
user-select: none;
width: 101px;
height: 36px;
font-size: 14px;
font-family: Source Han Sans CN;
font-weight: 400;
line-height: 36px;
box-sizing: border-box;
&:hover {
opacity: 0.7;
}
}
.share {
color: #333333;
background: #f2f6ff;
border: 1px solid #dcdcdc;
margin-right: 10px;
}
.order {
background: #0054ff;
color: #ffffff;
border: none;
}
}
.img {
width: 90px;
margin-right: 12px;
display: flex;
align-items: center;
justify-content: center;
img {
width: 90px;
height: 90px;
border-radius: 50%;
}
}
.content {
display: inline-block;
width: 390px;
.line {
font-size: 16px;
font-family: Source Han Sans CN;
font-weight: 400;
color: #666666;
margin: 10px 0;
span {
font-size: 16px;
font-family: Source Han Sans CN;
font-weight: 500;
color: #333;
}
}
}
.keywords {
flex: 1;
width: 129px;
height: 129px;
}
.tit {
width: 100%;
overflow: hidden;
cursor: pointer;
.text {
margin-right: 200px;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
font-size: 20px;
font-family: Source Han Sans CN;
font-weight: bold;
color: #333333;
}
}
}
</style>