AI商情-行业洞察12行业分类

master
fuxiaochun 2023-08-15 11:43:37 +08:00
parent f2710407ff
commit a186705d45
10 changed files with 778 additions and 2 deletions

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

View File

@ -178,6 +178,20 @@ const validate = () => {
return false;
}
}
if (loginType.value == 'password') {
if (!account.value) {
showToast('请输入手机号码或邮箱!');
return false;
}
if (!(telReg.test(account.value) || emailReg.test(account.value))) {
showToast('请输入有效的手机号码或邮箱!');
return false;
}
if (!password.value) {
showToast('请输入密码!');
return false;
}
}
return true;
};

View File

@ -1,7 +1,7 @@
<template>
<div class="header">
<div class="logo">logo</div>
<div class="title">首页</div>
<div class="title">{{$route.meta.title}}</div>
<div class="nav">
<div class="navBtn" @click.stop="toggleMenu"><van-icon name="wap-nav" size="0.6rem" /></div>
<div class="menuBox" @click.stop="" v-if="showMenu">
@ -16,7 +16,7 @@
<ul class="menu">
<li :class="{ active: route.meta.group === 'home' }" @click="jump('/')"></li>
<li>AI助理</li>
<li>AI商</li>
<li :class="{ active: route.meta.group === 'business' }" @click="jump('/business')">AI</li>
<li>AI传播</li>
<li>AI献策</li>
<li :class="{ active: route.meta.group === 'vip' }">会员服务</li>

View File

@ -47,6 +47,42 @@ const router = createRouter({
},
]
},
{
path: "business",
name: "business",
meta: {
title: "AI商情",
group: 'business'
},
component: () => import("@/views/business/index.vue"),
},
{
path: 'business/insight',
name: 'insight',
meta: {
title: 'AI商情-行业洞察',
group: 'business'
},
component: () => import("@/views/business/insight.vue"),
},
{
path: 'business/insight/category/:cid',
name: 'insightCategory',
meta: {
title: 'AI商情-行业洞察',
group: 'business'
},
component: () => import("@/views/business/list.vue"),
},
{
path: 'business/insight/detail/:cid/:id',
name: 'insightDetail',
meta: {
title: 'AI商情-行业洞察',
group: 'business'
},
component: () => import("@/views/business/detail.vue"),
},
]
}
],

View File

@ -0,0 +1,147 @@
<template>
<div class="listBox">
<template v-if="dataList != null">
<ul v-if="dataList.length > 0">
<li :key="item.id" v-for="item in dataList" @click="goDetail(item.id)">
<img :src="item.cover" :alt="item.title">
<div class="title">
<h2>{{item.title}}</h2>
<span>{{ DateFormat(new Date(item.published_at * 1000), 'yyyy.MM.dd')}}</span>
</div>
<div class="desc">{{item.description }}</div>
</li>
</ul>
<div class="placeholder" v-else>{{ placeholder }}</div>
</template>
<template v-else>
<div class="placeholder">{{ placeholder }}</div>
</template>
</div>
</template>
<script setup>
import { ref, onMounted } from 'vue';
import http from '@/io/http';
import { showToast } from 'vant';
import { DateFormat } from '@/utils/format.js';
import { useRouter, useRoute } from 'vue-router';
const router = useRouter();
const route = useRoute();
const props = defineProps({
cid: {
cid: Object,
default: {}
}
})
const pageSize = ref(15);
const pageNum = ref(1);
const result = ref({});
const dataList = ref([]);
const placeholder = ref('');
onMounted(()=>{
getList();
});
const getList = ()=>{
placeholder.value = '数据加载中...';
let params = {
category_id: props.cid,
type: 'business',
per_page: pageSize.value,
page: pageNum.value
};
http('/api/article', params, 'get').then(res => {
result.value = res.data;
dataList.value = res.data.data || [];
placeholder.value = dataList.value.length == 0 ? '暂无数据' : '';
}).catch(err => {
showToast(err.message);
placeholder.value = '数据加载失败';
});
};
const goDetail = (id) => {
router.push(`/insights/category/${props.cid}/${id}`);
};
</script>
<style lang="scss" scoped>
.listBox{
margin-top: 20px;
ul{
display: flex;
flex-wrap: wrap;
}
li{
width: 370px;
height: 305px;
background: #D6D6DD;
border-radius: 3px;
border: 2px solid #D6D6DD;
margin: 0 17px 34px 17px;
color: #333;
cursor: pointer;
img{
width: 364px;
height: 205px;
display: block;
margin: 0 auto;
}
.title{
height: 36px;
width: 100%;
padding: 17px;
display: flex;
justify-content: space-between;
align-items: center;
h2{
height: 36px;
font-weight: bold;
font-size: 18px;
line-height: 36px;
margin-right: 10px;
flex: 1;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
span{
height: 36px;
line-height: 36px;
display: inline-block;
font-size: 12px;
}
}
.desc{
padding: 5px 10px;
font-size: 12px;
line-height: 22px;
}
}
.pagesBox{
width: 100%;
height: 40px;
display: flex;
justify-content: center;
align-items: center;
color: #FFF;
a{
color: #FFF;
}
}
.placeholder{
width: 100%;
height: 300px;
display: flex;
justify-content: center;
align-items: center;
font-size: 14px;
color: #FFF;
}
}
</style>

View File

@ -0,0 +1,283 @@
<template>
<BackPage title="上一页" :url="`/insights/category/${cid}`">
<div class="pageContainer">
<div class="mainBox">
<div class="breadNav">
<router-link to="/home">首页</router-link><span>&gt;</span>
<router-link to="/insights">AI商情</router-link><span>&gt;</span>
<router-link to="/insights/category">行业洞察</router-link><span>&gt;</span>
<router-link :to="`/insights/category/${category.id}`" v-if="category.id">{{category.name}}</router-link><span v-if="category.id">&gt;</span>
<span>详情</span>
</div>
<div class="article" v-if="detail">
<h1 class="title">{{detail.title}}</h1>
<div class="props">
<span>作者{{detail.author }}</span>
<span>责编{{detail.editor }}</span>
<span>{{DateFormat(new Date(detail.published_at * 1000), 'yyyy.MM.dd')}}</span>
</div>
<div class="info">
<div v-html="detail.content"></div>
</div>
<!-- <div class="recommend">
<div class="blockTitle">推荐文章</div>
<ul>
<li>
<div class="img"><img src="http://madjs.com/d/file/2021/06-09/c0d0de22384d1f0e4ea06ee74e60c59c.jpg" alt=""></div>
<div class="info">
<h3>政策最新解读</h3>
<p>ChatGPT全名ChatGenerative Pre-trai...</p>
<span>2023.05.19</span>
</div>
</li>
<li>
<div class="img"><img src="http://madjs.com/d/file/2021/06-09/c0d0de22384d1f0e4ea06ee74e60c59c.jpg" alt=""></div>
<div class="info">
<h3>政策最新解读</h3>
<p>ChatGPT全名ChatGenerative Pre-trai...</p>
<span>2023.05.19</span>
</div>
</li>
<li>
<div class="img"><img src="http://madjs.com/d/file/2021/06-09/c0d0de22384d1f0e4ea06ee74e60c59c.jpg" alt=""></div>
<div class="info">
<h3>政策最新解读</h3>
<p>ChatGPT全名ChatGenerative Pre-trai...</p>
<span>2023.05.19</span>
</div>
</li>
<li>
<div class="img"><img src="http://madjs.com/d/file/2021/06-09/c0d0de22384d1f0e4ea06ee74e60c59c.jpg" alt=""></div>
<div class="info">
<h3>政策最新解读</h3>
<p>ChatGPT全名ChatGenerative Pre-trai...</p>
<span>2023.05.19</span>
</div>
</li>
<li>
<div class="img"><img src="http://madjs.com/d/file/2021/06-09/c0d0de22384d1f0e4ea06ee74e60c59c.jpg" alt=""></div>
<div class="info">
<h3>政策最新解读</h3>
<p>ChatGPT全名ChatGenerative Pre-trai...</p>
<span>2023.05.19</span>
</div>
</li>
<li>
<div class="img"><img src="http://madjs.com/d/file/2021/06-09/c0d0de22384d1f0e4ea06ee74e60c59c.jpg" alt=""></div>
<div class="info">
<h3>政策最新解读</h3>
<p>ChatGPT全名ChatGenerative Pre-trai...</p>
<span>2023.05.19</span>
</div>
</li>
</ul>
</div> -->
</div>
<div class="loadingBox" v-else>...</div>
</div>
<AiAssistant></AiAssistant>
</div>
</BackPage>
</template>
<script setup>
import { LeftCircleOutlined } from '@ant-design/icons-vue';
import { ref, onBeforeMount, onMounted } from 'vue';
import http from '@/io/http';
import { message } from 'ant-design-vue';
import { useRouter, useRoute } from 'vue-router';
import { DateFormat } from '@/utils/format.js';
import AiAssistant from '@/views/chat/components/ai-assistant.vue';
import BackPage from '@/components/BackPage/index.vue'
const router = useRouter();
const route = useRoute();
const cid = ref(route.params.cid);
const id = ref(route.params.id);
const category = ref({});
const detail = ref();
onBeforeMount(()=>{
getCategories();
});
onMounted(()=>{
getDetail();
});
const getCategories = () => {
let params = { type_key: 'business' };
http('/api/keywords', params, 'get').then(res => {
category.value = res.data.filter(v => v.id == cid.value)[0];
}).catch(err => {
message.error(err.message);
});
};
const getDetail = ()=>{
http(`/api/article/${id.value}`, {}, 'get').then(res => {
detail.value = res.data;
}).catch(err => {
message.error(err.message);
});
};
const goBack = () => {
router.back();
};
</script>
<style lang="scss" scoped>
.pageContainer{
color: #FFF;
width: 90rem;
margin: 0 auto;
display: flex;
justify-content: space-between;
.mainBox{
flex: 1;
background: #242527;
padding: 20px;
}
.sidebar{
width: 260px;
margin-left: 20px;
.pageNav{
width: 100%;
padding: 20px 0;
display: flex;
justify-content: flex-end;
align-items: center;
.prePage{
height: 36px;
padding-left: 40px;
background: url('@/assets/images/icon_left_arrow_circle@2x.png') no-repeat left center;
background-size: 36px 36px;
line-height: 36px;
cursor: pointer;
&:hover{
text-decoration: underline;
}
}
}
.sideBlock{
width: 100%;
margin-top: 20px;
}
}
.breadNav{
height: 30px;
line-height: 30px;
color: #999;
span{
padding: 0 5px;
}
a{
color: #999;
&:hover{
color: #FFF;
}
}
}
.loadingBox{
width: 100%;
height: 400px;
display: flex;
justify-content: center;
align-items: center;
font-size: 14px;
}
.article{
padding: 20px 0;
.title{
font-size: 27px;
line-height: 30px;
text-align: center;
padding: 10px 0;
}
.props{
width: 100%;
text-align: center;
line-height: 30px;
color: #999;
span{
display: inline-block;
margin: 10px;
}
}
.info{
line-height: 1.5;
:deep(p){
padding: 10px 0;
}
:deep(strong){
font-weight: bold;
}
:deep(b){
font-weight: bold;
}
:deep(h1){
font-weight: bold;
}
:deep(img){
max-width: 100%;
display: block;
margin: 10px auto;
}
}
.recommend{
padding: 30px 0;
.blockTitle{
height: 46px;
line-height: 45px;
border-bottom: 1px solid #666;
font-size: 18px;
font-weight: bold;
}
ul{
display: flex;
flex-wrap: wrap;
li{
width: 50%;
padding-right: 30px;
display: flex;
margin-top: 30px;
.img{
width: 120px;
height: 168px;
overflow: hidden;
img{
width: 120px;
height: 168px;
}
}
.info{
flex: 1;
margin-left: 15px;
height: 168px;
display: flex;
flex-direction: column;
justify-content: space-between;
h3{
font-size: 14px;
font-weight: bold;
padding-bottom: 10px;
}
p{
padding: 10px 0;
font-size: 12px;
line-height: 22px;
flex: 1;
}
span{
color: #999;
font-size: 12px;
}
}
}
}
}
}
}
</style>

View File

@ -0,0 +1,14 @@
<template>
<div>
AI商情首页
<router-link to="/business/insight">行业洞察</router-link>
</div>
</template>
<script setup>
</script>
<style lang="scss" scoped>
</style>

View File

@ -0,0 +1,133 @@
<template>
<div class="pageContainer">
<ul class="categoryBox" v-if="categories">
<li :key="item.id" v-for="item in categories" @click="goListPage(item.id)">
<img :src="item.image" :alt="item.name">
<div class="title">{{ item.name }}</div>
</li>
</ul>
<div class="loadingBox" v-else>...</div>
</div>
</template>
<script setup>
// 12
import { ref, onBeforeMount, onMounted } from 'vue';
import http from '@/io/http';
import { showToast } from 'vant';
import { useRouter } from 'vue-router';
const router = useRouter();
const categories = ref();
onBeforeMount(() => {
let params = { type_key: 'business' };
http('/api/keywords', params, 'get').then(res => {
categories.value = res.data || [];
}).catch(err => {
showToast(err.message);
});
});
const goListPage = (id) => {
router.push('/business/insight/category/' + id);
};
</script>
<style lang="scss" scoped>
.pageContainer {
color: #FFF;
padding: 90px 65px;
min-height: 100%;
.loadingBox {
width: 100%;
height: 100%;
display: flex;
justify-content: center;
align-items: center;
font-size: 30px;
}
.categoryBox {
width: 100%;
position: relative;
display: flex;
flex-wrap: wrap;
justify-content: space-between;
&::before {
content: '';
display: block;
width: 200px;
height: 110px;
background: url('@/assets/images/12jobs_cube1.png') no-repeat center;
background-size: contain;
position: absolute;
top: -55px;
left: -45px;
z-index: 0;
}
&::after {
content: '';
display: block;
width: 200px;
height: 143px;
background: url('@/assets/images/12jobs_cube2.png') no-repeat center;
background-size: contain;
position: absolute;
bottom: -70px;
right: -50px;
z-index: 0;
}
li {
width: 300px;
height: 160px;
border: 1px solid #666;
margin-top: 15px;
position: relative;
cursor: pointer;
background: #000;
z-index: 5;
&:hover {
border-color: #FFF;
}
img {
width: 298px;
height: 158px;
display: block;
opacity: 0.7;
font-size: 23px;
}
.title {
width: 100%;
height: 30px;
font-size: 28px;
line-height: 30px;
font-weight: bold;
position: absolute;
bottom: 25px;
padding-left: 30px;
&::before {
content: '';
position: absolute;
left: 11px;
top: 5px;
width: 5px;
height: 24px;
background: #3662FE;
border-radius: 2px;
}
}
}
}
}
</style>

View File

@ -0,0 +1,149 @@
<template>
<div class="pageContainer">
<div class="banner" :style="`background-image: url(${banner.picture})`">
<div class="bannerContent">
<div class="desc">
<h2>{{banner.name}}</h2>
<p>{{banner.description }}</p>
</div>
</div>
</div>
<div class="mainBox">
<ul class="menu">
<li :class="{active: cid == item.id}" @click="jump(item.id)" v-for="item in categories">{{item.name}}</li>
</ul>
<CardList :key="cid" :cid="cid"></CardList>
</div>
</div>
</template>
<script setup>
import { ref, onBeforeMount, onMounted, onUpdated, watch } from 'vue';
import http from '@/io/http';
import { showToast } from 'vant';
import { useRouter, useRoute } from 'vue-router';
import CardList from './components/CategoryCardList.vue';
const router = useRouter();
const route = useRoute();
const cid = ref(route.params.cid);
const banner = ref({});
const categories = ref([]);
onBeforeMount(() => {
getBanner();
getCategories();
});
onUpdated(()=>{
cid.value = route.params.cid;
});
watch(cid, (newCid, oldCid)=>{
if(newCid !== oldCid){
getBanner();
}
});
const getBanner = ()=>{
let params = {key: 'pc_business'};
http('/api/banner', params, 'get').then(res => {
banner.value = Array.isArray(res.data) ? res.data[0] : {};
}).catch(err => {
showToast(err.message);
});
};
const getCategories = ()=>{
let params = { type_key: 'business' };
http('/api/keywords', params, 'get').then(res => {
categories.value = res.data || [];
}).catch(err => {
showToast(err.message);
});
};
const goBack = () => {
router.push('/insights/category');
};
const jump = (cid)=>{
router.push(`/insights/category/${cid}`);
};
</script>
<style lang="scss" scoped>
.pageContainer{
width: 100%;
color: #FFF;
.banner{
width: 100%;
height: 17.6rem;
background-color: rgba($color: #FFF, $alpha: 0.5);
background-repeat: no-repeat;
background-size: contain;
background-position: center center;
.bannerContent{
width: 90rem;
height: 17.6rem;
margin: 0 auto;
position: relative;
}
.desc{
width: 100%;
height: 100%;
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
text-align: center;
h2{
font-size: 36px;
}
p{
width: 326px;
font-size: 12px;
line-height: 20px;
padding: 10px 0;
}
}
.nav{
position: absolute;
top: 38px;
right: 20px;
font-size: 16px;
cursor: pointer;
line-height: 30px;
display: flex;
align-items: center;
span{
margin-left: 10px;
}
}
}
.mainBox{
width: 90rem;
margin: 20px auto;
.menu{
display: flex;
padding: 10px 0;
flex-wrap: wrap;
li{
padding: 0 20px;
border-radius: 3px;
color: #999;
line-height: 30px;
margin-left: 17px;
margin-bottom: 10px;
cursor: pointer;
&:hover,
&.active{
background: #3662FE;
color: #FFF;
}
}
}
}
}
</style>