Merge remote-tracking branch 'origin/main' into feature/0905_登录注册流程重构
# Conflicts: # src/App.vue # src/views/components/login/index.vue # src/views/components/management/person/index.vue # src/views/login/style.scss
This commit is contained in:
@ -1,13 +1,15 @@
|
||||
<template>
|
||||
<a-select allow-search v-model="selectedValue" placeholder="请选择账号" allow-clear filterable @change="handleChange">
|
||||
<a-option v-for="account in filteredAccounts" :key="account.id" :value="account.id" :label="account.name">
|
||||
<Select showSearch v-model:value="selectedValue" placeholder="请选择账号" allowClear filterable @change="handleChange">
|
||||
<Option v-for="account in filteredAccounts" :key="account.id" :value="account.id" :label="account.name">
|
||||
{{ account.name }}
|
||||
</a-option>
|
||||
</a-select>
|
||||
</Option>
|
||||
</Select>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ref, computed, onMounted } from 'vue';
|
||||
import { Select } from 'ant-design-vue';
|
||||
const { Option } = Select;
|
||||
import { ref, onMounted } from 'vue';
|
||||
import { getPlacementAccountsList } from '@/api/all/propertyMarketing';
|
||||
|
||||
// 定义账号对象类型
|
||||
|
||||
@ -1,13 +1,15 @@
|
||||
<template>
|
||||
<a-select allow-search v-model="selectedValue" placeholder="请选择计划" allow-clear filterable @change="handleChange">
|
||||
<a-option v-for="item in listData" :key="item.id" :value="item.id" :label="item.name">
|
||||
<Select showSearch v-model:value="selectedValue" placeholder="请选择计划" allowClear filterable @change="handleChange">
|
||||
<Option v-for="item in listData" :key="item.id" :value="item.id" :label="item.name">
|
||||
{{ item.name }}
|
||||
</a-option>
|
||||
</a-select>
|
||||
</Option>
|
||||
</Select>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ref, computed, onMounted } from 'vue';
|
||||
import { Select } from 'ant-design-vue';
|
||||
const { Option } = Select;
|
||||
import { ref, computed, onMounted, type PropType } from 'vue';
|
||||
import { getplacementAccountProjectsLlist } from '@/api/all/propertyMarketing';
|
||||
|
||||
interface Account {
|
||||
@ -17,7 +19,7 @@ interface Account {
|
||||
|
||||
const props = defineProps({
|
||||
modelValue: {
|
||||
type: Array,
|
||||
type: Array as PropType<number[]>,
|
||||
default: () => [],
|
||||
},
|
||||
});
|
||||
@ -25,7 +27,7 @@ const props = defineProps({
|
||||
const emit = defineEmits(['update:modelValue', 'change']);
|
||||
|
||||
// 响应式数据
|
||||
const selectedValue = ref(props.modelValue);
|
||||
const selectedValue = ref<number | undefined>(props.modelValue?.[0]);
|
||||
const allAccounts = ref<Account[]>([]);
|
||||
const listData = ref<Account[]>([]);
|
||||
const loading = ref(false);
|
||||
|
||||
@ -1,13 +1,13 @@
|
||||
<template>
|
||||
<view>
|
||||
<topHeader ref="topHeaderRef" @search="search"></topHeader>
|
||||
<a-space direction="vertical" class="bg-#fff rounded-8px w-100% py-0 px-20px mb-24px">
|
||||
<div class="bg-#fff rounded-8px w-100% py-0 px-20px mb-24px">
|
||||
<div class="title-row">
|
||||
<span class="title mr-4px">行业词云</span>
|
||||
<a-tooltip>
|
||||
<template #content>基于行业内内容提取的高频词汇。</template>
|
||||
<Tooltip>
|
||||
<template #title>基于行业内内容提取的高频词汇。</template>
|
||||
<icon-question-circle size="16" class="!color-#737478" />
|
||||
</a-tooltip>
|
||||
</Tooltip>
|
||||
</div>
|
||||
|
||||
<div class="multi-row-tag-cloud h-472px">
|
||||
@ -20,7 +20,7 @@
|
||||
class="tag-row"
|
||||
:style="{ justifyContent: row.align || 'center' }"
|
||||
>
|
||||
<a-tag
|
||||
<Tag
|
||||
v-for="(tag, tagIndex) in row.tags"
|
||||
:key="tagIndex"
|
||||
class="cursor-pointer"
|
||||
@ -39,16 +39,14 @@
|
||||
@mouseenter="hoverTag = tag"
|
||||
@mouseleave="hoverTag = null"
|
||||
>
|
||||
<a-space>
|
||||
<a-tooltip :content="`性价比:${Number(tag.rate * 100)}%`" position="tl">
|
||||
<a-space>{{ tag.term }}</a-space>
|
||||
</a-tooltip>
|
||||
</a-space>
|
||||
</a-tag>
|
||||
<Tooltip :title="`性价比:${Number(tag.rate * 100)}%`" placement="topLeft">
|
||||
<span>{{ tag.term }}</span>
|
||||
</Tooltip>
|
||||
</Tag>
|
||||
</div>
|
||||
</template>
|
||||
</div>
|
||||
</a-space>
|
||||
</div>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
@ -56,6 +54,7 @@
|
||||
import topHeader from './topHeader.vue';
|
||||
import { ref, computed } from 'vue';
|
||||
import { fetchindustryTerms } from '@/api/all/index';
|
||||
import { Tooltip, Tag } from 'ant-design-vue';
|
||||
|
||||
const topHeaderRef = ref();
|
||||
// 从topHeader获取统一的状态
|
||||
@ -170,7 +169,7 @@ const processTagData = (apiData) => {
|
||||
color: #6d4cfe !important;
|
||||
border-color: #6d4cfe !important;
|
||||
}
|
||||
:deep(.arco-modal-body) {
|
||||
:deep(.ant-modal-body) {
|
||||
padding: 0px;
|
||||
}
|
||||
|
||||
@ -199,7 +198,7 @@ const processTagData = (apiData) => {
|
||||
}
|
||||
|
||||
/* 悬停放大效果 */
|
||||
a-tag:hover {
|
||||
.ant-tag:hover {
|
||||
transform: scale(1.1);
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
@ -2,88 +2,99 @@
|
||||
<view>
|
||||
<topHeader ref="topHeaderRef" @search="search"></topHeader>
|
||||
<!-- tabel -->
|
||||
<a-space
|
||||
direction="vertical"
|
||||
class="bg-#fff rounded-8px w-100% py-0 px-20px mb-24px"
|
||||
>
|
||||
<div class="bg-#fff rounded-8px w-100% py-0 px-20px mb-24px">
|
||||
<div class="title-row">
|
||||
<span class="title mr-4px">行业热门话题洞察</span>
|
||||
<a-tooltip>
|
||||
<template #content>基于社交内容平台的行业数据,分析用户关注的热门话题与趋势。</template>
|
||||
<Tooltip>
|
||||
<template #title>基于社交内容平台的行业数据,分析用户关注的热门话题与趋势。</template>
|
||||
<icon-question-circle size="16" class="!color-#737478" />
|
||||
</a-tooltip>
|
||||
</Tooltip>
|
||||
</div>
|
||||
<a-table
|
||||
:columns="columns"
|
||||
:data="dataList"
|
||||
:filter-icon-align-left="alignLeft"
|
||||
:scroll="true"
|
||||
<Table
|
||||
:dataSource="dataList"
|
||||
:pagination="false"
|
||||
:showSorterTooltip="false"
|
||||
@change="handleChange"
|
||||
>
|
||||
<template #empty>
|
||||
<Table.Column
|
||||
v-for="column in columns"
|
||||
:key="column.dataIndex"
|
||||
:title="column.title"
|
||||
:dataIndex="column.dataIndex"
|
||||
:width="column.width"
|
||||
:minWidth="column.minWidth"
|
||||
:sortable="column.sortable"
|
||||
>
|
||||
<template v-if="column.slotName === 'rank'" #customRender="{ record }">
|
||||
<img v-if="record.rank == 1" :src="topImages[0]" style="width: 25px; height: 17px" />
|
||||
<img v-else-if="record.rank == 2" :src="topImages[1]" style="width: 25px; height: 17px" />
|
||||
<img v-else-if="record.rank == 3" :src="topImages[2]" style="width: 25px; height: 17px" />
|
||||
<span v-else>{{ record.rank }}</span>
|
||||
</template>
|
||||
<template v-else-if="column.slotName === 'keywords'" #customRender="{ record }">
|
||||
<Tag
|
||||
v-for="item in record.keywords"
|
||||
:key="item"
|
||||
class="!rounded-2px !px-8px !py-1px !bg-#F2F3F5 !h-22px !color-#3C4043 mb-5px mr-5px"
|
||||
>{{ item }}</Tag
|
||||
>
|
||||
</template>
|
||||
<template v-else-if="column.slotName === 'hot'" #customRender="{ record }">
|
||||
<img
|
||||
v-for="i in record.hot"
|
||||
:key="i"
|
||||
:src="starImages[i - 1]"
|
||||
style="width: 16px; height: 16px"
|
||||
class="mr-2px"
|
||||
/>
|
||||
</template>
|
||||
<template v-else-if="column.slotName === 'sentiment'" #customRender="{ record }">
|
||||
<img v-if="record.felling == '2'" src="@/assets/img/hottranslation/good.png" class="w-24px h-24px" />
|
||||
<img v-else-if="record.felling == '1'" src="@/assets/img/hottranslation/normal.png" class="w-24px h-24px" />
|
||||
<img v-else-if="record.felling == '0'" src="@/assets/img/hottranslation/poor.png" class="w-24px h-24px" />
|
||||
</template>
|
||||
<template v-else-if="column.slotName === 'optional'" #customRender="{ record }">
|
||||
<Button type="primary" ghost @click="gotoDetail(record)">详情</Button>
|
||||
</template>
|
||||
<template v-else-if="column.titleSlotName === 'hotTitle'" #title>
|
||||
<div class="flex items-center">
|
||||
<span class="mr-8px">热度指数</span>
|
||||
<Tooltip>
|
||||
<template #title>综合话题出现频次、互动数据(如点赞、收藏、评论)加权计算的热度得分。</template>
|
||||
<icon-question-circle size="14" class="!color-#737478" />
|
||||
</Tooltip>
|
||||
</div>
|
||||
</template>
|
||||
<template v-else-if="column.titleSlotName === 'sentimentTitle'" #title>
|
||||
<div class="flex items-center">
|
||||
<span class="mr-8px">情感倾向</span>
|
||||
<Tooltip>
|
||||
<template #title
|
||||
>统计该行业下全部内容的情绪分布,选取占比最高的情绪类型作为该话题的整体情感倾向。</template
|
||||
>
|
||||
<icon-question-circle size="14" class="!color-#737478" />
|
||||
</Tooltip>
|
||||
</div>
|
||||
</template>
|
||||
</Table.Column>
|
||||
<template #emptyText>
|
||||
<NoData />
|
||||
</template>
|
||||
<template #hotTitle>
|
||||
<a-space>
|
||||
<span>热度指数</span>
|
||||
<a-tooltip>
|
||||
<template #content>综合话题出现频次、互动数据(如点赞、收藏、评论)加权计算的热度得分。</template>
|
||||
<icon-question-circle size="14" class="!color-#737478" />
|
||||
</a-tooltip>
|
||||
</a-space>
|
||||
</template>
|
||||
<template #sentimentTitle>
|
||||
<a-space>
|
||||
<span>情感倾向</span>
|
||||
<a-tooltip>
|
||||
<template #content
|
||||
>统计该行业下全部内容的情绪分布,选取占比最高的情绪类型作为该话题的整体情感倾向。</template
|
||||
>
|
||||
<icon-question-circle size="14" class="!color-#737478" />
|
||||
</a-tooltip>
|
||||
</a-space>
|
||||
</template>
|
||||
<template #rank="{ record }">
|
||||
<img v-if="record.rank == 1" :src="topImages[0]" style="width: 25px; height: 17px" />
|
||||
<img v-else-if="record.rank == 2" :src="topImages[1]" style="width: 25px; height: 17px" />
|
||||
<img v-else-if="record.rank == 3" :src="topImages[2]" style="width: 25px; height: 17px" />
|
||||
<span v-else>{{ record.rank }}</span>
|
||||
</template>
|
||||
<template #keywords="{ record }">
|
||||
<a-tag
|
||||
v-for="item in record.keywords"
|
||||
:key="item"
|
||||
class="!rounded-2px !px-8px !py-1px !bg-#F2F3F5 !h-22px !color-#3C4043 mb-5px mr-5px"
|
||||
>{{ item }}</a-tag
|
||||
>
|
||||
</template>
|
||||
<template #hot="{ record }">
|
||||
<img
|
||||
v-for="i in record.hot"
|
||||
:key="i"
|
||||
:src="starImages[i - 1]"
|
||||
style="width: 16px; height: 16px"
|
||||
class="mr-2px"
|
||||
/>
|
||||
</template>
|
||||
<template #sentiment="{ record }">
|
||||
<img v-if="record.felling == '2'" src="@/assets/img/hottranslation/good.png" class="w-24px h-24px" />
|
||||
<img v-else-if="record.felling == '1'" src="@/assets/img/hottranslation/normal.png" class="w-24px h-24px" />
|
||||
<img v-else-if="record.felling == '0'" src="@/assets/img/hottranslation/poor.png" class="w-24px h-24px" />
|
||||
</template>
|
||||
|
||||
<template #optional="{ record }">
|
||||
<a-button type="outline" class="!rounded-4px" @click="gotoDetail(record)">详情</a-button>
|
||||
</template>
|
||||
</a-table>
|
||||
</a-space>
|
||||
<a-modal :visible="visible" unmountOnClose modal-class="hot-translation-modal" width="640px" @cancel="handleCancel">
|
||||
</Table>
|
||||
</div>
|
||||
<Modal
|
||||
v-model:open="visible"
|
||||
unmountOnClose
|
||||
centered
|
||||
wrapClassName="hot-translation-modal"
|
||||
width="640px"
|
||||
@cancel="handleCancel"
|
||||
>
|
||||
<template #title>
|
||||
<span style="text-align: left; width: 100%">行业热门话题洞察</span>
|
||||
</template>
|
||||
<div>
|
||||
<a-space direction="vertical">
|
||||
<Space direction="vertical">
|
||||
<div class="mb-4px flex items-center">
|
||||
<p class="cts !mr-16px flex-shrink-0 w-48px">话题名称</p>
|
||||
<span class="cts">{{ topicInfo.name }}</span>
|
||||
@ -94,11 +105,11 @@
|
||||
</div>
|
||||
<div class="mb-4px flex items-center">
|
||||
<p class="cts !mr-16px flex-shrink-0 w-48px">关键词</p>
|
||||
<a-tag
|
||||
<Tag
|
||||
v-for="item in topicInfo.keywords"
|
||||
:key="item"
|
||||
class="mr-8px py-10px px-8px rounded-4px bg-#F2F3F5 cts !h-24px"
|
||||
>{{ item }}</a-tag
|
||||
>{{ item }}</Tag
|
||||
>
|
||||
</div>
|
||||
<div class="mb-4px flex items-center">
|
||||
@ -123,25 +134,27 @@
|
||||
<p class="!mr-16px w-48px cts relative top-2px">原始来源</p>
|
||||
<div class="flex flex-col">
|
||||
<div v-for="item in topicInfo.industry_topic_sources" :key="item" class="mb-18px flex items-center">
|
||||
<a-link style="background-color: initial" :href="item.link" target="_blank" class="!text-12px">{{
|
||||
<Link :href="item.link" target="_blank" class="!text-12px">{{
|
||||
item.title
|
||||
}}</a-link>
|
||||
}}</Link>
|
||||
<img src="@/assets/img/hottranslation/xhs.png" width="16" height="16" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</a-space>
|
||||
</Space>
|
||||
</div>
|
||||
<template #footer>
|
||||
<a-button size="large" @click="handleCancel">取消</a-button>
|
||||
<a-button type="primary" size="large" class="rounded-4px" @click="handleOk"> 确定 </a-button>
|
||||
<Button size="large" @click="handleCancel">取消</Button>
|
||||
<Button type="primary" size="large" @click="handleOk"> 确定 </Button>
|
||||
</template>
|
||||
</a-modal>
|
||||
</Modal>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import topHeader from './topHeader.vue';
|
||||
import { Modal, Button, Tooltip, Space, Table, Tag, Typography } from 'ant-design-vue';
|
||||
const { Link } = Typography;
|
||||
import { ref, computed } from 'vue';
|
||||
import { fetchIndustriesTree, fetchIndustryTopics, fetchIndustryTopicDetail } from '@/api/all/index';
|
||||
import star1 from '@/assets/img/hottranslation/star-fill1.png';
|
||||
@ -251,7 +264,7 @@ onMounted(() => {
|
||||
const getIndustriesTree = async () => {
|
||||
const res = await fetchIndustriesTree();
|
||||
industriesTree.value = res;
|
||||
selectedIndustry.value = res[0].id;
|
||||
selectedIndustry.value = res[0]?.id;
|
||||
getIndustryTopics();
|
||||
};
|
||||
|
||||
@ -320,7 +333,7 @@ const handleOk = () => {
|
||||
color: #6d4cfe !important;
|
||||
border-color: #6d4cfe !important;
|
||||
}
|
||||
:deep(.arco-modal-body) {
|
||||
:deep(.ant-modal-body) {
|
||||
padding: 0px;
|
||||
}
|
||||
|
||||
@ -374,7 +387,7 @@ const handleOk = () => {
|
||||
}
|
||||
}
|
||||
|
||||
.arco-modal-body {
|
||||
.ant-modal-body {
|
||||
padding: 12px 20px 0;
|
||||
.cts {
|
||||
color: var(--Text-2, #3c4043);
|
||||
|
||||
@ -3,102 +3,122 @@
|
||||
<view>
|
||||
<topHeader ref="topHeaderRef" @click="search"></topHeader>
|
||||
<!-- 重点品牌列表 -->
|
||||
<a-space
|
||||
<Space
|
||||
direction="vertical"
|
||||
class="bg-#fff rounded-8px w-100% py-0 px-20px mb-24px"
|
||||
>
|
||||
<div class="title-row">
|
||||
<span class="title mr-4px">重点品牌列表</span>
|
||||
<a-tooltip>
|
||||
<template #content
|
||||
<Tooltip>
|
||||
<template #title
|
||||
>基于该行业中近期提及频次高、用户互动活跃的品牌内容,筛选出关注度较高的代表性品牌。</template
|
||||
>
|
||||
<icon-question-circle size="16" class="!color-#737478" />
|
||||
</a-tooltip>
|
||||
</Tooltip>
|
||||
</div>
|
||||
<a-table
|
||||
:columns="columns"
|
||||
:data="dataList"
|
||||
:filter-icon-align-left="alignLeft"
|
||||
:scroll="true"
|
||||
<Table
|
||||
:dataSource="dataList"
|
||||
:pagination="false"
|
||||
:showSorterTooltip="false"
|
||||
@change="handleChange"
|
||||
>
|
||||
<template #empty>
|
||||
<Table.Column
|
||||
v-for="column in columns"
|
||||
:key="column.dataIndex"
|
||||
:title="column.title"
|
||||
:dataIndex="column.dataIndex"
|
||||
:width="column.width"
|
||||
:minWidth="column.minWidth"
|
||||
:sortable="column.sortable"
|
||||
>
|
||||
<template v-if="column.slotName === 'rank'" #customRender="{ record }">
|
||||
<img v-if="record.rank == 1" :src="topImages[0]" style="width: 25px; height: 17px" />
|
||||
<img v-else-if="record.rank == 2" :src="topImages[1]" style="width: 25px; height: 17px" />
|
||||
<img v-else-if="record.rank == 3" :src="topImages[2]" style="width: 25px; height: 17px" />
|
||||
<span v-else>{{ record.rank }}</span>
|
||||
</template>
|
||||
<template v-else-if="column.slotName === 'hot'" #customRender="{ record }">
|
||||
<img v-for="i in record.hot" :key="i" :src="starImages[i - 1]" style="width: 16px; height: 16px" />
|
||||
</template>
|
||||
<template v-else-if="column.slotName === 'trend'" #customRender="{ record }">
|
||||
<div class="flex items-center" :class="record.trend > 0 ? 'color-#F64B31' : 'color-#25C883'">
|
||||
<icon-arrow-up v-if="record.trend > 0" size="16" />
|
||||
<icon-arrow-down v-else size="16" />
|
||||
{{ `${(record.trend * 100).toFixed(2)}%` }}
|
||||
</div>
|
||||
</template>
|
||||
<template v-else-if="column.slotName === 'volumeRate'" #customRender="{ record }">
|
||||
<Statistic :value="record.volume_rate * 100" />%
|
||||
</template>
|
||||
<template v-else-if="column.titleSlotName === 'hotTitle'" #title>
|
||||
<Space>
|
||||
<span>热度指数</span>
|
||||
<Tooltip>
|
||||
<template #title>综合话题出现频次、互动数据(如点赞、收藏、评论)加权计算的热度得分。</template>
|
||||
<icon-question-circle size="14" class="!color-#737478" />
|
||||
</Tooltip>
|
||||
</Space>
|
||||
</template>
|
||||
<template v-else-if="column.titleSlotName === 'trendTitle'" #title>
|
||||
<Space>
|
||||
<span>变化幅度</span>
|
||||
<Tooltip>
|
||||
<template #title>仅基于品牌出现频次。</template>
|
||||
<icon-question-circle size="14" class="!color-#737478" />
|
||||
</Tooltip>
|
||||
</Space>
|
||||
</template>
|
||||
<template v-else-if="column.titleSlotName === 'volume_rateTitle'" #title>
|
||||
<Space>
|
||||
<span>占总声量比例</span>
|
||||
<Tooltip>
|
||||
<template #title>该品牌在当前周期内被提及的内容量,占整个行业内容总量的比例。</template>
|
||||
<icon-question-circle size="14" class="!color-#737478" />
|
||||
</Tooltip>
|
||||
</Space>
|
||||
</template>
|
||||
</Table.Column>
|
||||
<template #emptyText>
|
||||
<NoData />
|
||||
</template>
|
||||
<template #hotTitle>
|
||||
<a-space>
|
||||
<span>热度指数</span>
|
||||
<a-tooltip>
|
||||
<template #content>综合话题出现频次、互动数据(如点赞、收藏、评论)加权计算的热度得分。</template>
|
||||
<icon-question-circle size="14" class="!color-#737478" />
|
||||
</a-tooltip>
|
||||
</a-space>
|
||||
</template>
|
||||
<template #trendTitle>
|
||||
<a-space>
|
||||
<span>变化幅度</span>
|
||||
<a-tooltip>
|
||||
<template #content>仅基于品牌出现频次。</template>
|
||||
<icon-question-circle size="14" class="!color-#737478" />
|
||||
</a-tooltip>
|
||||
</a-space>
|
||||
</template>
|
||||
<template #volume_rateTitle>
|
||||
<a-space>
|
||||
<span>占总声量比例</span>
|
||||
<a-tooltip>
|
||||
<template #content>该品牌在当前周期内被提及的内容量,占整个行业内容总量的比例。</template>
|
||||
<icon-question-circle size="14" class="!color-#737478" />
|
||||
</a-tooltip>
|
||||
</a-space>
|
||||
</template>
|
||||
<template #rank="{ record }">
|
||||
<img v-if="record.rank == 1" :src="topImages[0]" style="width: 25px; height: 17px" />
|
||||
<img v-else-if="record.rank == 2" :src="topImages[1]" style="width: 25px; height: 17px" />
|
||||
<img v-else-if="record.rank == 3" :src="topImages[2]" style="width: 25px; height: 17px" />
|
||||
<span v-else>{{ record.rank }}</span>
|
||||
</template>
|
||||
<template #hot="{ record }">
|
||||
<img v-for="i in record.hot" :key="i" :src="starImages[i - 1]" style="width: 16px; height: 16px" />
|
||||
</template>
|
||||
<template #trend="{ record }">
|
||||
<div class="flex items-center" :class="record.trend > 0 ? 'color-#F64B31' : 'color-#25C883'">
|
||||
<icon-arrow-up v-if="record.trend > 0" size="16" />
|
||||
<icon-arrow-down v-else size="16" />
|
||||
{{ `${(record.trend * 100).toFixed(2)}%` }}
|
||||
</div>
|
||||
</template>
|
||||
<template #volumeRate="{ record }"> <a-statistic :value="record.volume_rate * 100" />% </template>
|
||||
</a-table>
|
||||
</a-space>
|
||||
</Table>
|
||||
</Space>
|
||||
<!-- 舆情 & 敏感动态-->
|
||||
<a-space
|
||||
<Space
|
||||
direction="vertical"
|
||||
class="bg-#fff rounded-8px w-100% py-0 px-20px mb-24px"
|
||||
>
|
||||
<div class="title-row">
|
||||
<span class="title mr-4px">舆情 & 敏感动态</span>
|
||||
<a-tooltip>
|
||||
<template #content
|
||||
<Tooltip>
|
||||
<template #title
|
||||
>基于情绪分析与敏感词识别,对行业内容中的负面或争议性话题进行监测,辅助判断舆情风险动态。</template
|
||||
>
|
||||
<icon-question-circle size="16" class="!color-#737478" />
|
||||
</a-tooltip>
|
||||
</Tooltip>
|
||||
</div>
|
||||
|
||||
<a-table :data="otherList" :columns="columns2" :pagination="false" :scroll="true" style="font-size: 12px">
|
||||
<template #empty>
|
||||
<Table :dataSource="otherList" :pagination="false" :showSorterTooltip="false" style="font-size: 12px">
|
||||
<Table.Column
|
||||
v-for="column in columns2"
|
||||
:key="column.dataIndex"
|
||||
:title="column.title"
|
||||
:dataIndex="column.dataIndex"
|
||||
:width="column.width"
|
||||
:minWidth="column.minWidth"
|
||||
:sortable="column.sortable"
|
||||
/>
|
||||
<template #emptyText>
|
||||
<NoData />
|
||||
</template>
|
||||
</a-table>
|
||||
</a-space>
|
||||
</Table>
|
||||
</Space>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import topHeader from './topHeader.vue';
|
||||
import { Tooltip, Space, Table, Statistic } from 'ant-design-vue';
|
||||
import { fetchFocusBrandsList, fetchEventDynamicsList } from '@/api/all/index';
|
||||
import { ref, onMounted, computed } from 'vue';
|
||||
import star1 from '@/assets/img/hottranslation/star-fill1.png';
|
||||
|
||||
@ -3,46 +3,46 @@
|
||||
<view>
|
||||
<topHeader ref="topHeaderRef" @search="search"></topHeader>
|
||||
<!-- 关键词热度榜 -->
|
||||
<a-space
|
||||
<Space
|
||||
direction="vertical"
|
||||
class="bg-#fff rounded-8px w-100% py-0 px-20px mb-20px"
|
||||
>
|
||||
<div class="title-row">
|
||||
<span class="title mr-4px">关键词热度榜</span>
|
||||
<a-tooltip>
|
||||
<template #content>基于该行业用户内容中提及频率较高的关键词,按热度进行排序,反映近期关注焦点。</template>
|
||||
<Tooltip>
|
||||
<template #title>基于该行业用户内容中提及频率较高的关键词,按热度进行排序,反映近期关注焦点。</template>
|
||||
<icon-question-circle size="16" class="!color-#737478" />
|
||||
</a-tooltip>
|
||||
</Tooltip>
|
||||
</div>
|
||||
|
||||
<a-table
|
||||
<Table
|
||||
:columns="columns"
|
||||
:data="dataList"
|
||||
:filter-icon-align-left="alignLeft"
|
||||
:scroll="true"
|
||||
:dataSource="dataList"
|
||||
:scroll="{ x: true }"
|
||||
:pagination="false"
|
||||
:showSorterTooltip="false"
|
||||
@change="handleChange"
|
||||
>
|
||||
<template #empty>
|
||||
<template #emptyText>
|
||||
<NoData />
|
||||
</template>
|
||||
<template #heatLevel>
|
||||
<a-space>
|
||||
<Space>
|
||||
<span>热度指数</span>
|
||||
<a-tooltip>
|
||||
<template #content>综合话题出现频次、互动数据(如点赞、收藏、评论)加权计算的热度得分。</template>
|
||||
<Tooltip>
|
||||
<template #title>综合话题出现频次、互动数据(如点赞、收藏、评论)加权计算的热度得分。</template>
|
||||
<icon-question-circle size="14" class="!color-#737478" />
|
||||
</a-tooltip>
|
||||
</a-space>
|
||||
</Tooltip>
|
||||
</Space>
|
||||
</template>
|
||||
<template #trendTitle>
|
||||
<a-space>
|
||||
<Space>
|
||||
<span>变化幅度</span>
|
||||
<a-tooltip>
|
||||
<template #content>仅基于关键词出现频次。</template>
|
||||
<Tooltip>
|
||||
<template #title>仅基于关键词出现频次。</template>
|
||||
<icon-question-circle size="14" class="!color-#737478" />
|
||||
</a-tooltip>
|
||||
</a-space>
|
||||
</Tooltip>
|
||||
</Space>
|
||||
</template>
|
||||
|
||||
<template #rank="{ record }">
|
||||
@ -52,7 +52,7 @@
|
||||
<span v-else>{{ record.rank }}</span>
|
||||
</template>
|
||||
<template #keywords="{ record }">
|
||||
<a-tag v-for="item in record.keywords" :key="item" style="margin-right: 5px">{{ item }}</a-tag>
|
||||
<Tag v-for="item in record.keywords" :key="item" style="margin-right: 5px">{{ item }}</Tag>
|
||||
</template>
|
||||
<template #hot="{ record }">
|
||||
<img v-for="i in record.hot" :key="i" :src="starImages[i - 1]" style="width: 16px; height: 16px" />
|
||||
@ -69,21 +69,21 @@
|
||||
{{ `${(record.trend * 100).toFixed(2)}%` }}
|
||||
</div>
|
||||
</template>
|
||||
</a-table>
|
||||
</a-space>
|
||||
</Table>
|
||||
</Space>
|
||||
<!-- 行业情绪 -->
|
||||
<a-space
|
||||
<Space
|
||||
direction="vertical"
|
||||
class="bg-#fff rounded-8px w-100% py-0 px-20px mb-24px"
|
||||
>
|
||||
<div class="title-row">
|
||||
<span class="title mr-4px">行业情绪</span>
|
||||
<a-tooltip>
|
||||
<template #content
|
||||
<Tooltip>
|
||||
<template #title
|
||||
>对该行业下用户内容进行情绪分析,按情绪类别统计占比,提取占比最高者作为行业情绪代表。</template
|
||||
>
|
||||
<icon-question-circle size="16" class="!color-#737478" />
|
||||
</a-tooltip>
|
||||
</Tooltip>
|
||||
</div>
|
||||
|
||||
<div class="flex items-center w-100%">
|
||||
@ -103,17 +103,16 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<a-table
|
||||
<Table
|
||||
class="flex-1"
|
||||
:columns="columns2"
|
||||
:data="sortedRowData"
|
||||
:span-method="spanMethod"
|
||||
:filter-icon-align-left="alignLeft"
|
||||
:scroll="true"
|
||||
:dataSource="sortedRowData"
|
||||
:scroll="{ x: true }"
|
||||
:pagination="false"
|
||||
:showSorterTooltip="false"
|
||||
@change="handleChange"
|
||||
>
|
||||
<template #empty>
|
||||
<template #emptyText>
|
||||
<NoData />
|
||||
</template>
|
||||
<template #felling="{ record }">
|
||||
@ -122,33 +121,33 @@
|
||||
<span>{{ fellingStatus[record.felling].label }}</span>
|
||||
</div>
|
||||
</template>
|
||||
</a-table>
|
||||
</Table>
|
||||
</div>
|
||||
</a-space>
|
||||
</Space>
|
||||
<!-- 新兴关键词 -->
|
||||
<a-space
|
||||
<Space
|
||||
direction="vertical"
|
||||
class="bg-#fff rounded-8px w-100% py-0 px-20px"
|
||||
>
|
||||
<div class="title-row">
|
||||
<span class="title mr-4px">新兴关键词</span>
|
||||
<a-tooltip>
|
||||
<template #content
|
||||
<Tooltip>
|
||||
<template #title
|
||||
>指当前周期中首次出现,或相较上一周期词频显著增长的关键词,反映近期出现的新关注点。</template
|
||||
>
|
||||
<icon-question-circle size="16" class="!color-#737478" />
|
||||
</a-tooltip>
|
||||
</Tooltip>
|
||||
</div>
|
||||
|
||||
<a-table
|
||||
<Table
|
||||
:columns="columns3"
|
||||
:data="keywordList"
|
||||
:filter-icon-align-left="alignLeft"
|
||||
:scroll="true"
|
||||
:dataSource="keywordList"
|
||||
:scroll="{ x: true }"
|
||||
:pagination="false"
|
||||
:showSorterTooltip="false"
|
||||
@change="handleChange"
|
||||
>
|
||||
<template #empty>
|
||||
<template #emptyText>
|
||||
<NoData />
|
||||
</template>
|
||||
<template #rank="{ record }">
|
||||
@ -181,23 +180,23 @@
|
||||
<img v-for="i in record.hot" :key="i" :src="starImages[i - 1]" style="width: 16px; height: 16px" />
|
||||
</template>
|
||||
|
||||
<template #hotTitle="{ record }">
|
||||
<a-space>
|
||||
<template #hotTitle>
|
||||
<Space>
|
||||
<span>当前热度指数</span>
|
||||
<a-tooltip>
|
||||
<template #content>综合关键词出现频次、互动表现(如点赞、收藏、评论)加权计算的热度得分。</template>
|
||||
<Tooltip>
|
||||
<template #title>综合关键词出现频次、互动表现(如点赞、收藏、评论)加权计算的热度得分。</template>
|
||||
<icon-question-circle size="16" class="!color-#737478" />
|
||||
</a-tooltip>
|
||||
</a-space>
|
||||
</Tooltip>
|
||||
</Space>
|
||||
</template>
|
||||
<template #trendTitle="{ record }">
|
||||
<a-space>
|
||||
<template #trendTitle>
|
||||
<Space>
|
||||
<span>变化幅度</span>
|
||||
<a-tooltip>
|
||||
<template #content>仅基于关键词出现频次。</template>
|
||||
<Tooltip>
|
||||
<template #title>仅基于关键词出现频次。</template>
|
||||
<icon-question-circle size="16" class="!color-#737478" />
|
||||
</a-tooltip>
|
||||
</a-space>
|
||||
</Tooltip>
|
||||
</Space>
|
||||
</template>
|
||||
<template #tred="{ record }">
|
||||
<div class="flex items-center" :class="record.trend > 0 ? 'color-#F64B31' : 'color-#25C883'">
|
||||
@ -207,15 +206,16 @@
|
||||
</div>
|
||||
</template>
|
||||
<template #optional="{ record }">
|
||||
<a-button type="outline" @click="gotoDetail(record)">详情</a-button>
|
||||
<Button type="primary" ghost @click="gotoDetail(record)">详情</Button>
|
||||
</template>
|
||||
</a-table>
|
||||
</a-space>
|
||||
</Table>
|
||||
</Space>
|
||||
<!-- modal -->
|
||||
<a-modal
|
||||
:visible="visible"
|
||||
modal-class="keyword-modal"
|
||||
<Modal
|
||||
v-model:open="visible"
|
||||
wrapClassName="keyword-modal"
|
||||
unmountOnClose
|
||||
centered
|
||||
width="640px"
|
||||
@ok="handleOk"
|
||||
@cancel="handleCancel"
|
||||
@ -224,7 +224,7 @@
|
||||
<span style="text-align: left; width: 100%">新兴关键词</span>
|
||||
</template>
|
||||
<div>
|
||||
<a-space direction="vertical">
|
||||
<Space direction="vertical">
|
||||
<div class="mb-12px flex items-center">
|
||||
<p class="cts !mr-16px flex-shrink-0 w-83px">话题名称</p>
|
||||
<span class="cts">{{ topicInfo.name }}</span>
|
||||
@ -250,25 +250,27 @@
|
||||
<p class="!mr-16px w-83px cts relative top-2px">原始来源</p>
|
||||
<div class="flex flex-col">
|
||||
<div v-for="item in topicInfo.industry_new_keyword_sources" :key="item" class="mb-18px flex items-center">
|
||||
<a-link style="background-color: initial" :href="item.link" target="_blank" class="!text-12px">{{
|
||||
<Link :href="item.link" target="_blank" class="!text-12px">{{
|
||||
item.title
|
||||
}}</a-link>
|
||||
}}</Link>
|
||||
<img src="@/assets/img/hottranslation/xhs.png" width="16" height="16" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</a-space>
|
||||
</Space>
|
||||
</div>
|
||||
<template #footer>
|
||||
<a-button size="large" @click="handleCancel">取消</a-button>
|
||||
<a-button type="primary" size="large" class="rounded-4px" @click="handleOk"> 确定 </a-button>
|
||||
<Button size="large" @click="handleCancel">取消</Button>
|
||||
<Button type="primary" size="large" @click="handleOk"> 确定 </Button>
|
||||
</template>
|
||||
</a-modal>
|
||||
</Modal>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import topHeader from './topHeader.vue';
|
||||
import { Modal, Button, Tooltip, Space, Table, Tag, Typography } from 'ant-design-vue';
|
||||
const { Link } = Typography;
|
||||
import {
|
||||
fetchKeywordTrendsList,
|
||||
fetchIndustryEmotions,
|
||||
@ -690,7 +692,7 @@ onMounted(() => {
|
||||
}
|
||||
}
|
||||
|
||||
.arco-modal-body {
|
||||
.ant-modal-body {
|
||||
padding: 12px 20px 0;
|
||||
.cts {
|
||||
color: var(--Text-2, #3c4043);
|
||||
|
||||
@ -1,97 +1,100 @@
|
||||
<template>
|
||||
<view>
|
||||
<!-- 头部 -->
|
||||
<a-space
|
||||
<Space
|
||||
direction="vertical"
|
||||
class="bg-#fff rounded-8px mb-20px"
|
||||
style="background-color: #fff; width: 100%; padding: 24px; color: #737478; font-size: 14px"
|
||||
>
|
||||
<a-space align="start" style="width: 100%; align-items: flex-start" class="mb-12px">
|
||||
<Space align="start" style="width: 100%; align-items: flex-start" class="mb-12px">
|
||||
<span style="flex-shrink: 0; line-height: 28px" class="mr-32px">行业大类</span>
|
||||
<div style="display: flex; flex-wrap: wrap; gap: 16px; width: 100%; align-items: flex-start">
|
||||
<a-tag
|
||||
<Tag
|
||||
v-for="item in industriesTree"
|
||||
:key="item.id"
|
||||
size="Medium"
|
||||
:checkable="true"
|
||||
:checked="selectedIndustry == item.id"
|
||||
style="padding: 10px 16px; border-radius: 30px; height: 28px"
|
||||
style="padding: 0 16px; border-radius: 30px; height: 28px"
|
||||
class="lh-28px cursor-pointer"
|
||||
:style="
|
||||
selectedIndustry == item.id
|
||||
? 'color: #6D4CFE; background-color: #F0EDFF'
|
||||
: 'color: #3C4043; background-color: #F7F8FA'
|
||||
"
|
||||
@check="handleIndustryCheck(item.id)"
|
||||
>{{ item.name }}</a-tag
|
||||
@click="handleIndustryCheck(item.id)"
|
||||
>{{ item.name }}</Tag
|
||||
>
|
||||
</div>
|
||||
</a-space>
|
||||
</Space>
|
||||
<!-- 二级类目 -->
|
||||
<a-space align="start" style="width: 100%; align-items: flex-start" class="mb-12px">
|
||||
<Space align="start" style="width: 100%; align-items: flex-start" class="mb-12px">
|
||||
<span style="flex-shrink: 0; line-height: 28px" class="mr-32px">二级类目</span>
|
||||
<div style="display: flex; flex-wrap: wrap; gap: 16px; width: 100%; align-items: flex-start">
|
||||
<a-tag
|
||||
<Tag
|
||||
v-for="item in subCategories"
|
||||
:key="item.id"
|
||||
size="Medium"
|
||||
size="small"
|
||||
:checkable="true"
|
||||
:checked="selectedSubCategory == item.id"
|
||||
style="padding: 10px 16px; border-radius: 30px; height: 28px"
|
||||
style="padding: 0 16px; border-radius: 30px; height: 28px"
|
||||
class="lh-28px cursor-pointer"
|
||||
:style="
|
||||
selectedSubCategory == item.id
|
||||
? 'color: #6d4cfe; background-color: #f0edff'
|
||||
: 'color: #3C4043; background-color: #F7F8FA'
|
||||
"
|
||||
@check="handleSubCategoryCheck(item.id)"
|
||||
>{{ item.name }}</a-tag
|
||||
@click="handleSubCategoryCheck(item.id)"
|
||||
>{{ item.name }}</Tag
|
||||
>
|
||||
</div>
|
||||
</a-space>
|
||||
<!-- </a-space> -->
|
||||
<a-space align="start" style="width: 100%; align-items: flex-start" class="mb-12px">
|
||||
</Space>
|
||||
<!-- </Space> -->
|
||||
<Space align="start" style="width: 100%; align-items: flex-start" class="mb-12px">
|
||||
<span style="flex-shrink: 0; line-height: 28px" class="mr-32px">时间筛选</span>
|
||||
<div style="display: flex; flex-wrap: wrap; gap: 16px; width: 100%; align-items: flex-start">
|
||||
<a-tag
|
||||
<Tag
|
||||
v-for="item in timePeriods"
|
||||
:key="item.value"
|
||||
size="Medium"
|
||||
:checkable="true"
|
||||
:checked="selectedTimePeriod == item.value"
|
||||
style="padding: 10px 16px; border-radius: 30px; height: 28px"
|
||||
class="lh-28px cursor-pointer"
|
||||
style="padding: 0 16px; border-radius: 30px; height: 28px"
|
||||
:style="
|
||||
selectedTimePeriod == item.value
|
||||
? 'color: #6d4cfe; background-color: #f0edff'
|
||||
: 'color: #3C4043; background-color: #F7F8FA'
|
||||
"
|
||||
@check="handleTimePeriodCheck(item.value)"
|
||||
@click="handleTimePeriodCheck(item.value)"
|
||||
>{{ item.label }}
|
||||
</a-tag>
|
||||
</Tag>
|
||||
</div>
|
||||
</a-space>
|
||||
</Space>
|
||||
<!-- 搜索区域 -->
|
||||
<a-space style="margin-left: 'auto'">
|
||||
<a-button type="primary" size="medium" @click="handleSearch">
|
||||
<Space style="margin-left: 'auto'">
|
||||
<Button type="primary" @click="handleSearch">
|
||||
<template #icon>
|
||||
<icon-search />
|
||||
<icon-search class="mr-8px"/>
|
||||
</template>
|
||||
<!-- Use the default slot to avoid extra spaces -->
|
||||
<template #default>搜索</template>
|
||||
</a-button>
|
||||
<a-button class="w-84px reset-btn" size="medium" @click="handleReset">
|
||||
</Button>
|
||||
<Button class="w-84px reset-btn" @click="handleReset">
|
||||
<template #icon>
|
||||
<icon-refresh />
|
||||
<icon-refresh class="mr-8px"/>
|
||||
</template>
|
||||
<template #default>重置</template>
|
||||
</a-button>
|
||||
</a-space>
|
||||
</a-space>
|
||||
</Button>
|
||||
</Space>
|
||||
</Space>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ref, computed } from 'vue';
|
||||
import { fetchIndustriesTree } from '@/api/all/index';
|
||||
|
||||
import { Button, Space, Tag } from 'ant-design-vue';
|
||||
const emit = defineEmits<(e: 'search') => void>();
|
||||
// 行业大类
|
||||
const industriesTree = ref([]);
|
||||
@ -139,6 +142,7 @@ const handleIndustryCheck = (id) => {
|
||||
};
|
||||
|
||||
const handleSubCategoryCheck = (id) => {
|
||||
console.log('handleSubCategoryCheck');
|
||||
selectedSubCategory.value = id;
|
||||
};
|
||||
|
||||
@ -185,7 +189,7 @@ const handleReset = () => {
|
||||
color: #6d4cfe !important;
|
||||
border-color: #6d4cfe !important;
|
||||
}
|
||||
:deep(.arco-modal-body) {
|
||||
:deep(.ant-modal-body) {
|
||||
padding: 0px;
|
||||
}
|
||||
.reset-btn {
|
||||
|
||||
@ -3,63 +3,71 @@
|
||||
<topHeader ref="topHeaderRef" @search="search"></topHeader>
|
||||
|
||||
<!-- 用户痛点观察 -->
|
||||
<a-space
|
||||
<Space
|
||||
direction="vertical"
|
||||
style="background-color: #fff; width: 100%; padding: 0 20px"
|
||||
class="bg-#fff rounded-8px mb-24px"
|
||||
>
|
||||
<div class="title-row">
|
||||
<span class="title mr-4px">用户痛点观察</span>
|
||||
<a-tooltip>
|
||||
<template #content
|
||||
<Tooltip>
|
||||
<template #title
|
||||
>基于用户内容中的情绪分析与表达模式,提取反复出现的负面倾向主题,反映典型使用痛点。</template
|
||||
>
|
||||
<icon-question-circle size="16" class="!color-#737478" />
|
||||
</a-tooltip>
|
||||
</Tooltip>
|
||||
</div>
|
||||
<a-table
|
||||
:columns="columns"
|
||||
:data="dataList"
|
||||
:filter-icon-align-left="alignLeft"
|
||||
:scroll="true"
|
||||
<Table
|
||||
:dataSource="dataList"
|
||||
:pagination="false"
|
||||
:showSorterTooltip="false"
|
||||
@change="handleChange"
|
||||
>
|
||||
<template #empty>
|
||||
<Table.Column
|
||||
v-for="column in columns"
|
||||
:key="column.dataIndex"
|
||||
:title="column.title"
|
||||
:dataIndex="column.dataIndex"
|
||||
:width="column.width"
|
||||
:minWidth="column.minWidth"
|
||||
:sortable="column.sortable"
|
||||
>
|
||||
<template v-if="column.slotName === 'rank'" #customRender="{ record }">
|
||||
<img v-if="record.rank == 1" :src="topImages[0]" style="width: 25px; height: 17px" />
|
||||
<img v-else-if="record.rank == 2" :src="topImages[1]" style="width: 25px; height: 17px" />
|
||||
<img v-else-if="record.rank == 3" :src="topImages[2]" style="width: 25px; height: 17px" />
|
||||
<span v-else>{{ record.rank }}</span>
|
||||
</template>
|
||||
<template v-else-if="column.slotName === 'keywords'" #customRender="{ record }">
|
||||
<Tag
|
||||
v-for="item in record.keywords"
|
||||
:key="item"
|
||||
class="!rounded-2px !px-8px !py-1px !bg-#F2F3F5 !h-22px !color-#3C4043 mb-5px mr-5px"
|
||||
>{{ item }}</Tag
|
||||
>
|
||||
</template>
|
||||
<template v-else-if="column.slotName === 'frequency'" #customRender="{ record }">
|
||||
<Tag
|
||||
:class="`!rounded-2px !px-8px !py-1px !bg-${frequencyStatus[record.frequency].bgColor} !h-22px !color-${
|
||||
frequencyStatus[record.frequency].color
|
||||
}`"
|
||||
>{{ frequencyStatus[record.frequency].label }}</Tag
|
||||
>
|
||||
</template>
|
||||
<template v-else-if="column.slotName === 'optional'" #customRender="{ record }">
|
||||
<Button type="primary" ghost @click="gotoDetail(record)">详情</Button>
|
||||
</template>
|
||||
</Table.Column>
|
||||
<template #emptyText>
|
||||
<NoData />
|
||||
</template>
|
||||
<template #rank="{ record }">
|
||||
<img v-if="record.rank == 1" :src="topImages[0]" style="width: 25px; height: 17px" />
|
||||
<img v-else-if="record.rank == 2" :src="topImages[1]" style="width: 25px; height: 17px" />
|
||||
<img v-else-if="record.rank == 3" :src="topImages[2]" style="width: 25px; height: 17px" />
|
||||
<span v-else>{{ record.rank }}</span>
|
||||
</template>
|
||||
<template #keywords="{ record }">
|
||||
<a-tag
|
||||
v-for="item in record.keywords"
|
||||
:key="item"
|
||||
class="!rounded-2px !px-8px !py-1px !bg-#F2F3F5 !h-22px !color-#3C4043 mb-5px mr-5px"
|
||||
>{{ item }}</a-tag
|
||||
>
|
||||
</template>
|
||||
<template #frequency="{ record }">
|
||||
<a-tag
|
||||
:class="`!rounded-2px !px-8px !py-1px !bg-${frequencyStatus[record.frequency].bgColor} !h-22px !color-${
|
||||
frequencyStatus[record.frequency].color
|
||||
}`"
|
||||
>{{ frequencyStatus[record.frequency].label }}</a-tag
|
||||
>
|
||||
</template>
|
||||
</Table>
|
||||
</Space>
|
||||
|
||||
<template #optional="{ record }">
|
||||
<a-button type="outline" class="!rounded-4px" @click="gotoDetail(record)">详情</a-button>
|
||||
</template>
|
||||
</a-table>
|
||||
</a-space>
|
||||
|
||||
<a-modal
|
||||
:visible="visible"
|
||||
modal-class="user-pain-points-modal"
|
||||
<Modal
|
||||
v-model:open="visible"
|
||||
wrapClassName="user-pain-points-modal"
|
||||
centered
|
||||
unmountOnClose
|
||||
width="640px"
|
||||
@ok="handleOk"
|
||||
@ -69,27 +77,27 @@
|
||||
<span style="text-align: left; width: 100%">用户痛点观察</span>
|
||||
</template>
|
||||
<div>
|
||||
<a-space direction="vertical" style="font-size: 12px">
|
||||
<Space direction="vertical" style="font-size: 12px">
|
||||
<div class="mb-12px flex items-center">
|
||||
<p class="cts !mr-16px flex-shrink-0 w-60px">痛点</p>
|
||||
<span class="cts">{{ topicInfo.name }}</span>
|
||||
</div>
|
||||
<div class="mb-12px flex items-center">
|
||||
<p class="cts !mr-16px flex-shrink-0 w-60px">关键词</p>
|
||||
<a-tag
|
||||
<Tag
|
||||
v-for="item in topicInfo.keywords"
|
||||
:key="item"
|
||||
class="mr-8px py-10px px-8px rounded-4px bg-#F2F3F5 cts !h-24px"
|
||||
>{{ item }}</a-tag
|
||||
>{{ item }}</Tag
|
||||
>
|
||||
</div>
|
||||
<div class="mb-12px flex items-center">
|
||||
<p class="cts !mr-16px flex-shrink-0 w-60px">频次</p>
|
||||
<a-tag
|
||||
<Tag
|
||||
:class="`!rounded-2px !px-8px !py-1px !bg-${
|
||||
frequencyStatus[topicInfo.frequency].bgColor
|
||||
} !h-22px !color-${frequencyStatus[topicInfo.frequency].color}`"
|
||||
>{{ frequencyStatus[topicInfo.frequency].label }}</a-tag
|
||||
>{{ frequencyStatus[topicInfo.frequency].label }}</Tag
|
||||
>
|
||||
</div>
|
||||
<div class="mb-12px flex items-center">
|
||||
@ -100,25 +108,27 @@
|
||||
<p class="cts !mr-16px flex-shrink-0 w-60px">原始来源</p>
|
||||
<div class="flex flex-col">
|
||||
<div v-for="item in topicInfo.user_pain_point_sources" :key="item" class="mb-18px flex items-center">
|
||||
<a-link style="background-color: initial" :href="item.link" target="_blank" class="!text-12px">{{
|
||||
<Link :href="item.link" target="_blank" class="!text-12px">{{
|
||||
item.title
|
||||
}}</a-link>
|
||||
}}</Link>
|
||||
<img src="@/assets/img/hottranslation/xhs.png" width="16" height="16" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</a-space>
|
||||
</Space>
|
||||
</div>
|
||||
<template #footer>
|
||||
<a-button size="large" @click="handleCancel">取消</a-button>
|
||||
<a-button type="primary" size="large" class="rounded-4px" @click="handleOk"> 确定 </a-button>
|
||||
<Button size="large" @click="handleCancel">取消</Button>
|
||||
<Button type="primary" size="large" @click="handleOk"> 确定 </Button>
|
||||
</template>
|
||||
</a-modal>
|
||||
</Modal>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import topHeader from './topHeader.vue';
|
||||
import { Modal, Button, Tooltip, Space, Table, Tag, Typography } from 'ant-design-vue';
|
||||
const { Link } = Typography;
|
||||
import { fetchUserPainPointsDetail, fetchUserPainPointsList } from '@/api/all/index';
|
||||
import { ref, onMounted, computed } from 'vue';
|
||||
import top1 from '@/assets/img/captcha/top1.svg';
|
||||
@ -286,16 +296,16 @@ const search = () => {
|
||||
</style>
|
||||
<style lang="scss">
|
||||
.user-pain-points-modal {
|
||||
.arco-modal-header {
|
||||
.ant-modal-header {
|
||||
border-bottom: none;
|
||||
height: 56px;
|
||||
padding: 0 20px;
|
||||
.arco-modal-title {
|
||||
.ant-modal-title {
|
||||
justify-content: flex-start;
|
||||
}
|
||||
}
|
||||
|
||||
.arco-modal-body {
|
||||
.ant-modal-body {
|
||||
padding: 12px 20px 0;
|
||||
.cts {
|
||||
color: var(--Text-2, #3c4043);
|
||||
@ -311,7 +321,7 @@ const search = () => {
|
||||
}
|
||||
}
|
||||
|
||||
.arco-modal-footer {
|
||||
.ant-modal-footer {
|
||||
display: flex;
|
||||
height: 64px;
|
||||
padding: 0px 20px;
|
||||
|
||||
@ -6,52 +6,52 @@
|
||||
<div class="bg-#fff rounded-8px w-100% py-0 px-20px w-600px mr-24px">
|
||||
<div class="title-row">
|
||||
<span class="title mr-4px">性别分布</span>
|
||||
<a-tooltip>
|
||||
<template #content>基于社交内容平台中用户资料、互动行为及语义特征进行智能识别与估算。</template>
|
||||
<Tooltip>
|
||||
<template #title>基于社交内容平台中用户资料、互动行为及语义特征进行智能识别与估算。</template>
|
||||
<icon-question-circle size="16" class="!color-#737478" />
|
||||
</a-tooltip>
|
||||
</Tooltip>
|
||||
</div>
|
||||
<a-space v-if="genderData.length > 0">
|
||||
<Space v-if="genderData.length > 0">
|
||||
<div id="container" class="w-300px h-300px"></div>
|
||||
|
||||
<a-space direction="vertical" style="font-size: 14px">
|
||||
<a-space>
|
||||
<Space direction="vertical" style="font-size: 14px">
|
||||
<Space>
|
||||
<span style="width: 8px; height: 8px; background-color: #f64b31; border-radius: 50%"></span>
|
||||
<span>女性</span>
|
||||
<span>{{ (girlData.rate * 100).toFixed(2) }}%</span>
|
||||
<span>TGI</span>
|
||||
<span>{{ girlData.tgi }}</span>
|
||||
</a-space>
|
||||
<a-space>
|
||||
</Space>
|
||||
<Space>
|
||||
<span style="width: 8px; height: 8px; background-color: #2a59f3; border-radius: 50%"></span>
|
||||
<span>男性</span>
|
||||
<span>{{ (boyData.rate * 100).toFixed(2) }}%</span>
|
||||
<span>TGI</span>
|
||||
<span>{{ boyData.tgi }}</span>
|
||||
</a-space>
|
||||
</a-space>
|
||||
</a-space>
|
||||
</Space>
|
||||
</Space>
|
||||
</Space>
|
||||
<div v-else>
|
||||
<NoData class="w-100% h-100%" />
|
||||
</div>
|
||||
</div>
|
||||
<!-- 2. 年龄分布 -->
|
||||
<div class="bg-#fff rounded-8px w-100% py-0 px-20px flex-1 flex flex-col">
|
||||
<a-space style="display: flex; justify-content: space-between; width: 100%; font-size: 12px">
|
||||
<Space style="display: flex; justify-content: space-between; width: 100%; font-size: 12px">
|
||||
<div class="title-row">
|
||||
<span class="title mr-4px">年龄分布</span>
|
||||
<a-tooltip>
|
||||
<template #content>基于社交平台的公开信息、内容偏好与行为模式,通过算法进行年龄段归类和统计。</template>
|
||||
<Tooltip>
|
||||
<template #title>基于社交平台的公开信息、内容偏好与行为模式,通过算法进行年龄段归类和统计。</template>
|
||||
<icon-question-circle size="16" class="!color-#737478" />
|
||||
</a-tooltip>
|
||||
</Tooltip>
|
||||
</div>
|
||||
<a-space v-if="ageValueData.length > 0" align="center">
|
||||
<Space v-if="ageValueData.length > 0" align="center">
|
||||
<span style="width: 16px; height: 8px; background-color: #6d4cfe; border-radius: 2px"></span>
|
||||
<span style="color: #6d4cfe">占比</span>
|
||||
<span style="width: 16px; height: 8px; background-color: #f64b31; border-radius: 2px"></span>
|
||||
<span style="color: #f64b31">TGI比</span>
|
||||
</a-space>
|
||||
</a-space>
|
||||
</Space>
|
||||
</Space>
|
||||
<div v-if="ageValueData.length === 0" class="w-100% flex-1">
|
||||
<NoData />
|
||||
</div>
|
||||
@ -61,17 +61,17 @@
|
||||
<div class="bg-#fff rounded-8px w-100% py-0 px-20px flex-1 pb-20px">
|
||||
<div class="title-row">
|
||||
<span class="title mr-4px">地域分布</span>
|
||||
<a-tooltip>
|
||||
<template #content>基于社交平台的IP归属地、位置标签、内容发布地等数据推测用户活跃区域。</template>
|
||||
<Tooltip>
|
||||
<template #title>基于社交平台的IP归属地、位置标签、内容发布地等数据推测用户活跃区域。</template>
|
||||
<icon-question-circle size="16" class="!color-#737478" />
|
||||
</a-tooltip>
|
||||
</Tooltip>
|
||||
</div>
|
||||
<div class="flex">
|
||||
<a-space direction="vertical">
|
||||
<Space direction="vertical">
|
||||
<div id="chinaMap" style="height: 416px; width: 640px"></div>
|
||||
<a-space direction="vertical" style="font-size: 14px">
|
||||
<Space direction="vertical" style="font-size: 14px">
|
||||
<span class="cts">搜索指数</span>
|
||||
<a-space>
|
||||
<Space>
|
||||
<span class="cts">高</span>
|
||||
<span
|
||||
v-for="item in 5"
|
||||
@ -86,44 +86,38 @@
|
||||
}"
|
||||
></span>
|
||||
<span class="cts">低</span>
|
||||
</a-space>
|
||||
</a-space>
|
||||
</a-space>
|
||||
</Space>
|
||||
</Space>
|
||||
</Space>
|
||||
<div class="flex flex-col h-486px">
|
||||
<a-tabs default-active-key="1" class="h-100%" @change="tabChange">
|
||||
<a-tab-pane key="1" title="省份">
|
||||
<a-table :data="geoList" :pagination="false" class="h-100%" :scroll="{ y: '100%' }">
|
||||
<template #empty>
|
||||
<Tabs defaultActiveKey="1" class="h-100%" @change="tabChange" size="large">
|
||||
<TabPane key="1" tab="省份">
|
||||
<Table :dataSource="geoList" :pagination="false" class="h-100%" :scroll="{ y: '100%' }" :showSorterTooltip="false">
|
||||
<template #emptyText>
|
||||
<NoData />
|
||||
</template>
|
||||
<template #columns>
|
||||
<a-table-column title="排名" data-index="rank" />
|
||||
<a-table-column title="省份" data-index="geo" />
|
||||
<a-table-column title="分布占比" data-index="rate" />
|
||||
|
||||
<a-table-column title="TGI指数" data-index="tgi" />
|
||||
</template>
|
||||
</a-table>
|
||||
</a-tab-pane>
|
||||
<a-tab-pane key="2" title="城市">
|
||||
<a-table :data="geoList" :pagination="false" class="h-100%" :scroll="{ y: '100%' }">
|
||||
<template #empty>
|
||||
<Column title="排名" dataIndex="rank" />
|
||||
<Column title="省份" dataIndex="geo" />
|
||||
<Column title="分布占比" dataIndex="rate" />
|
||||
<Column title="TGI指数" dataIndex="tgi" />
|
||||
</Table>
|
||||
</TabPane>
|
||||
<TabPane key="2" tab="城市">
|
||||
<Table :dataSource="geoList" :pagination="false" class="h-100%" :scroll="{ y: '100%' }" :showSorterTooltip="false">
|
||||
<template #emptyText>
|
||||
<NoData />
|
||||
</template>
|
||||
<template #columns>
|
||||
<a-table-column title="排名" data-index="rank" />
|
||||
<a-table-column title="城市" data-index="geo" />
|
||||
<a-table-column title="分布占比" data-index="rate">
|
||||
<template #cell="{ record }">
|
||||
<span class="cts">{{ (record.rate * 100).toFixed(2) }}%</span>
|
||||
</template>
|
||||
</a-table-column>
|
||||
|
||||
<a-table-column title="TGI指数" data-index="tgi" />
|
||||
</template>
|
||||
</a-table>
|
||||
</a-tab-pane>
|
||||
</a-tabs>
|
||||
<Column title="排名" dataIndex="rank" />
|
||||
<Column title="城市" dataIndex="geo" />
|
||||
<Column title="分布占比" dataIndex="rate">
|
||||
<template #customRender="{ record }">
|
||||
<span class="cts">{{ (record.rate * 100).toFixed(2) }}%</span>
|
||||
</template>
|
||||
</Column>
|
||||
<Column title="TGI指数" dataIndex="tgi" />
|
||||
</Table>
|
||||
</TabPane>
|
||||
</Tabs>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@ -133,11 +127,15 @@
|
||||
<script setup>
|
||||
import topHeader from './topHeader.vue';
|
||||
import { fetchAgeDistributionsList, fetchGeoDistributionsList, fetchGenderDistributionsList } from '@/api/all/index';
|
||||
import { ref, onMounted, computed } from 'vue';
|
||||
import { ref, onMounted, computed, watch, nextTick } from 'vue';
|
||||
import * as echarts from 'echarts';
|
||||
import chinaJson from '@/assets/maps/china.json';
|
||||
|
||||
echarts.registerMap('china', chinaJson);
|
||||
import { Tabs, Tooltip, Space, Table } from 'ant-design-vue';
|
||||
const { TabPane } = Tabs;
|
||||
const { Column } = Table;
|
||||
|
||||
const scope = ref(1); // 地域范围,1-省,2-市
|
||||
const chartInstance = (ref < echarts.ECharts) | (null > null);
|
||||
const topHeaderRef = ref();
|
||||
|
||||
@ -2,40 +2,44 @@
|
||||
<div class="bg-#fff rounded-8px w-100% py-0 px-20px pb-24px">
|
||||
<div class="title-row">
|
||||
<span class="title">账号管理</span>
|
||||
<a-button type="outline" class="add-account-button" @click="handleAddAccount">添加子账号</a-button>
|
||||
<Button type="primary" ghost class="add-account-button" @click="handleAddAccount">添加子账号</Button>
|
||||
</div>
|
||||
<a-table
|
||||
:columns="columns"
|
||||
:data="dataSource"
|
||||
<Table
|
||||
:dataSource="dataSource"
|
||||
:pagination="pagination"
|
||||
:showSorterTooltip="false"
|
||||
class="mt-8px"
|
||||
@page-change="handlePageChange"
|
||||
@page-size-change="handlePageSizeChange"
|
||||
@change="handleTableChange"
|
||||
>
|
||||
<template #empty>
|
||||
<Table.Column title="手机号" dataIndex="mobile">
|
||||
<template #customRender="{ record }">
|
||||
<div class="flex item-center pt-13px pb-13px">
|
||||
<span class="mr-4px">{{ record.mobile }}</span>
|
||||
<Tag v-if="record.type === 0" class="primary-account">主账号</Tag>
|
||||
<Tag v-else class="sub-account">子账号</Tag>
|
||||
</div>
|
||||
</template>
|
||||
</Table.Column>
|
||||
<Table.Column title="操作" dataIndex="action" width="120">
|
||||
<template #customRender="{ record }">
|
||||
<Button
|
||||
v-if="record.type !== 0"
|
||||
class="delete-button"
|
||||
size="small"
|
||||
type="primary"
|
||||
ghost
|
||||
danger
|
||||
@click="openDeleteModal(record)"
|
||||
>
|
||||
删除
|
||||
</Button>
|
||||
</template>
|
||||
</Table.Column>
|
||||
<template #emptyText>
|
||||
<NoData />
|
||||
</template>
|
||||
<template #mobile="{ record }">
|
||||
<div class="flex item-center pt-13px pb-13px">
|
||||
<span class="mr-4px">{{ record.mobile }}</span>
|
||||
<a-tag v-if="record.type === 0" class="primary-account">主账号</a-tag>
|
||||
<a-tag v-else class="sub-account">子账号</a-tag>
|
||||
</div>
|
||||
</template>
|
||||
<template #action="{ record }">
|
||||
<a-button
|
||||
v-if="record.type !== 0"
|
||||
class="delete-button"
|
||||
size="mini"
|
||||
type="outline"
|
||||
status="danger"
|
||||
@click="openDeleteModal(record)"
|
||||
>
|
||||
删除
|
||||
</a-button>
|
||||
</template>
|
||||
</a-table>
|
||||
<Modal v-model:visible="addAccountVisible" width="480px" title="添加子账号" :okText="okText" @ok="handleOk">
|
||||
</Table>
|
||||
<Modal v-model:open="addAccountVisible" centered width="480px" title="添加子账号" :okText="okText" @ok="handleOk" >
|
||||
<div v-if="canAddAccount" class="add-account-container">
|
||||
<h2 class="add-account-title">生成企业专属链接,成员通过访问即可注册并加入企业账号。</h2>
|
||||
<p class="add-account-subtitle">子账号可独立登录,权限继承主账号配置。</p>
|
||||
@ -52,15 +56,15 @@
|
||||
<p class="cannot-add-account-subtitle">如需添加更多子账号,您可联系销售人员进行购买和权限扩展。</p>
|
||||
</div>
|
||||
</Modal>
|
||||
<CustomerServiceModal v-model:visible="customerServiceVisible" />
|
||||
<DeleteModal v-model:visible="deleteVisible" :title="deleteTitle" @ok="handleDelete">
|
||||
<p class="delete-modal-content">删除后,该账号将无法登录您的企业。</p>
|
||||
<CustomerServiceModal v-model:open="customerServiceVisible" centered/>
|
||||
<DeleteModal v-model:open="deleteVisible" centered :content="deleteTitle" @ok="handleDelete" @cancel="deleteVisible = false">
|
||||
</DeleteModal>
|
||||
</div>
|
||||
</template>
|
||||
<script setup lang="ts">
|
||||
import Container from '@/components/container.vue';
|
||||
import { ref, onMounted, reactive, computed } from 'vue';
|
||||
import { Button, Table, message, Tag } from 'ant-design-vue';
|
||||
|
||||
import { fetchSubAccountPage, removeEnterpriseAccount, getEnterpriseInviteCode } from '@/api/all';
|
||||
import Modal from '@/components/modal.vue';
|
||||
import DeleteModal from '@/components/delete-modal.vue';
|
||||
@ -82,10 +86,10 @@ const columns = [
|
||||
const dataSource = ref([]);
|
||||
const pagination = reactive({
|
||||
total: 0,
|
||||
showPageSize: true,
|
||||
showTotal: true,
|
||||
defaultCurrent: 1,
|
||||
defaultPageSize: 10,
|
||||
showSizeChanger: true,
|
||||
showTotal: (total: number, range: [number, number]) => `共 ${total} 条记录`,
|
||||
current: 1,
|
||||
pageSize: 10,
|
||||
});
|
||||
|
||||
const params = reactive({
|
||||
@ -120,13 +124,12 @@ const currentSelectAccount = ref();
|
||||
|
||||
const { copy, copied, isSupported } = useClipboard({ source: inviteUrl });
|
||||
|
||||
function handlePageChange(current: number) {
|
||||
params.page = current;
|
||||
getSubAccount();
|
||||
}
|
||||
|
||||
function handlePageSizeChange(pageSize: number) {
|
||||
params.page_size = pageSize;
|
||||
function handleTableChange(paginationInfo: any, filters: any, sorter: any) {
|
||||
params.page = paginationInfo.current;
|
||||
params.page_size = paginationInfo.pageSize;
|
||||
// 更新分页状态
|
||||
pagination.current = paginationInfo.current;
|
||||
pagination.pageSize = paginationInfo.pageSize;
|
||||
getSubAccount();
|
||||
}
|
||||
|
||||
@ -155,13 +158,13 @@ function handleOk() {
|
||||
return;
|
||||
}
|
||||
if (!isSupported) {
|
||||
AMessage.error('您的浏览器不支持复制,请手动复制!');
|
||||
message.error('您的浏览器不支持复制,请手动复制!');
|
||||
}
|
||||
copy(inviteUrl.value);
|
||||
if (!copied) {
|
||||
AMessage.error('复制失败,请手动复制!');
|
||||
message.error('复制失败,请手动复制!');
|
||||
}
|
||||
AMessage.success('复制成功!');
|
||||
message.success('复制成功!');
|
||||
}
|
||||
|
||||
function openDeleteModal(record: { id: number; mobile: string }) {
|
||||
@ -172,7 +175,7 @@ function openDeleteModal(record: { id: number; mobile: string }) {
|
||||
|
||||
async function handleDelete() {
|
||||
await removeEnterpriseAccount(currentSelectAccount.value.id);
|
||||
AMessage.success('移除成功!');
|
||||
message.success('移除成功!');
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
@ -275,14 +278,7 @@ onMounted(() => {
|
||||
color: var(--Text-2, rgba(60, 64, 67, 1));
|
||||
}
|
||||
}
|
||||
.delete-modal-content {
|
||||
margin-left: 34px;
|
||||
margin-top: 16px;
|
||||
font-family: $font-family-medium;
|
||||
font-weight: 400;
|
||||
font-size: 12px;
|
||||
color: var(--Text-2, rgba(60, 64, 67, 1));
|
||||
}
|
||||
|
||||
.title-row {
|
||||
display: flex;
|
||||
height: 64px;
|
||||
|
||||
@ -3,39 +3,53 @@
|
||||
<div class="title-row">
|
||||
<span class="title">企业信息</span>
|
||||
</div>
|
||||
<a-table :columns="columns" :data="dataSource" :pagination="false" class="mt-8px">
|
||||
<template #empty>
|
||||
<Table :dataSource="dataSource" :pagination="false" :showSorterTooltip="false" class="mt-8px">
|
||||
<Table.Column title="企业信息" dataIndex="info">
|
||||
<template #customRender="{ record }">
|
||||
{{ record.name }}
|
||||
</template>
|
||||
</Table.Column>
|
||||
<Table.Column title="操作" dataIndex="action" width="120">
|
||||
<template #customRender>
|
||||
<Button class="edit-button" size="small" type="primary" ghost @click="handleUpdate">修改</Button>
|
||||
</template>
|
||||
</Table.Column>
|
||||
<template #emptyText>
|
||||
<NoData />
|
||||
</template>
|
||||
<template #info="{ record }">
|
||||
{{ record.name }}
|
||||
</template>
|
||||
<template #action>
|
||||
<a-button class="edit-button" size="mini" type="outline" @click="handleUpdate">修改</a-button>
|
||||
</template>
|
||||
</a-table>
|
||||
<Modal v-model:visible="infoVisible" width="480px" title="修改企业名称" :okText="okText" @ok="handleOk">
|
||||
</Table>
|
||||
<Modal
|
||||
v-model:open="infoVisible"
|
||||
width="480px"
|
||||
centered
|
||||
title="修改企业名称"
|
||||
:okText="okText"
|
||||
@ok="handleOk"
|
||||
cancelText="取消"
|
||||
>
|
||||
<p class="tips">
|
||||
企业名称只能修改2次,请谨慎操作。<span
|
||||
>(剩余{{ enterpriseInfo!.update_name_quota - enterpriseInfo!.used_update_name_count }}次)
|
||||
</span>
|
||||
</p>
|
||||
<a-form
|
||||
<Form
|
||||
:model="form"
|
||||
:rules="rules"
|
||||
class="form"
|
||||
:label-col-props="{ span: 6, offset: 0 }"
|
||||
:wrapper-col-props="{ span: 18, offset: 0 }"
|
||||
label-align="left"
|
||||
>
|
||||
<a-form-item required field="name" label="新企业名称">
|
||||
<a-input v-model.trim="form.name" size="small" :disabled="!canUpdate" placeholder="请输入新企业名称" />
|
||||
</a-form-item>
|
||||
</a-form>
|
||||
<FormItem required name="name" label="新企业名称">
|
||||
<Input v-model:value.trim="form.name" size="small" :disabled="!canUpdate" placeholder="请输入新企业名称" />
|
||||
</FormItem>
|
||||
</Form>
|
||||
</Modal>
|
||||
<CustomerServiceModal v-model:visible="customerServiceVisible" />
|
||||
<CustomerServiceModal v-model:open="customerServiceVisible" centered />
|
||||
</div>
|
||||
</template>
|
||||
<script setup lang="ts">
|
||||
import { Button, Form, FormItem, Input, Table, message } from 'ant-design-vue';
|
||||
import Container from '@/components/container.vue';
|
||||
import Modal from '@/components/modal.vue';
|
||||
import { ref, reactive, computed } from 'vue';
|
||||
@ -48,6 +62,16 @@ const form = reactive({
|
||||
name: '',
|
||||
});
|
||||
|
||||
const rules = {
|
||||
name: [
|
||||
{
|
||||
required: true,
|
||||
message: '请输入新企业名称',
|
||||
trigger: ['blur'],
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
const enterpriseInfo = computed(() => {
|
||||
return store.enterpriseInfo ?? {};
|
||||
});
|
||||
@ -98,7 +122,7 @@ async function handleOk() {
|
||||
await updateEnterpriseName({ name: form.name });
|
||||
store.setEnterpriseName(form.name);
|
||||
store.incUsedUpdateNameCount();
|
||||
AMessage.success('修改成功!');
|
||||
message.success('修改成功!');
|
||||
}
|
||||
</script>
|
||||
|
||||
|
||||
@ -1,32 +1,37 @@
|
||||
<template>
|
||||
<div class="bg-#fff rounded-16px w-100% p-36px">
|
||||
<p class="title mb-32px">个人信息</p>
|
||||
<a-table :columns="columns" :data="dataSource" :pagination="false" class="mt-8px">
|
||||
<template #empty>
|
||||
<Table :dataSource="dataSource" :pagination="false" :showSorterTooltip="false" class="mt-8px">
|
||||
<Table.Column title="用户信息" dataIndex="info">
|
||||
<template #customRender="{ record }">
|
||||
<div class="pt-3px pb-3px">
|
||||
<Avatar :src="record.head_image" :size="32" />
|
||||
{{ record.name || '-' }}
|
||||
<icon-edit size="13" class="ml-8px" @click="openEditInfoModal" />
|
||||
</div>
|
||||
</template>
|
||||
</Table.Column>
|
||||
<Table.Column title="手机号" dataIndex="mobile">
|
||||
<template #customRender="{ record }">
|
||||
{{ record.mobile.replace(/(\d{3})\d{4}(\d{4})/, '$1****$2') }}
|
||||
<icon-edit size="13" class="ml-8px" @click="openEditMobileModal" />
|
||||
</template>
|
||||
</Table.Column>
|
||||
<template #emptyText>
|
||||
<NoData />
|
||||
</template>
|
||||
<template #info="{ record }">
|
||||
<div class="pt-3px pb-3px">
|
||||
<a-avatar :image-url="record.head_image" :size="32" />
|
||||
{{ record.name || '-' }}
|
||||
<icon-edit size="13" class="ml-8px" @click="openEditInfoModal" />
|
||||
</div>
|
||||
</template>
|
||||
<template #mobile="{ record }">
|
||||
{{ record.mobile.replace(/(\d{3})\d{4}(\d{4})/, '$1****$2') }}
|
||||
<icon-edit size="13" class="ml-8px" @click="openEditMobileModal" />
|
||||
</template>
|
||||
</a-table>
|
||||
<Modal v-model:visible="infoVisible" title="修改用户信息" @ok="handleSubmitUserInfo">
|
||||
<a-form
|
||||
</Table>
|
||||
<Modal v-model:open="infoVisible" centered title="修改用户信息" @ok="handleSubmitUserInfo">
|
||||
<Form
|
||||
class="form"
|
||||
:rules="rules"
|
||||
:model="userInfoForm"
|
||||
:label-col-props="{ span: 3, offset: 0 }"
|
||||
:wrapper-col-props="{ span: 21, offset: 0 }"
|
||||
>
|
||||
<a-form-item field="head_image" label="头像">
|
||||
<FormItem name="head_image" label="头像">
|
||||
<div class="flex items-center">
|
||||
<a-avatar :image-url="userInfoForm.file_url" :size="48" />
|
||||
<Avatar :src="userInfoForm.file_url" :size="48" />
|
||||
<span class="upload-button" @click="triggerFileInput">
|
||||
<input
|
||||
ref="uploadInputRef"
|
||||
@ -35,40 +40,40 @@
|
||||
style="display: none"
|
||||
@change="handleFileChange"
|
||||
/>
|
||||
<a-button><icon-upload />上传新头像</a-button>
|
||||
<Button><icon-upload />上传新头像</Button>
|
||||
</span>
|
||||
</div>
|
||||
</a-form-item>
|
||||
<a-form-item field="name" label="昵称">
|
||||
<a-input v-model.trim="userInfoForm.name" placeholder="请输入昵称" />
|
||||
</a-form-item>
|
||||
</a-form>
|
||||
</FormItem>
|
||||
<FormItem name="name" label="昵称">
|
||||
<Input v-model:value="userInfoForm.name" placeholder="请输入昵称" />
|
||||
</FormItem>
|
||||
</Form>
|
||||
</Modal>
|
||||
<Modal v-model:visible="imageVisible" title="头像裁剪">
|
||||
<Modal v-model:open="imageVisible" centered title="头像裁剪">
|
||||
<VueCropper></VueCropper>
|
||||
</Modal>
|
||||
<Modal v-model:visible="mobileVisible" title="修改手机号" @ok="handleUpdateMobile">
|
||||
<a-form
|
||||
<Modal v-model:open="mobileVisible" centered title="修改手机号" @ok="handleUpdateMobile">
|
||||
<Form
|
||||
ref="formRef"
|
||||
:model="form"
|
||||
class="form"
|
||||
:rules="formRules"
|
||||
:label-col-props="{ span: 5, offset: 0 }"
|
||||
:wrapper-col-props="{ span: 19, offset: 0 }"
|
||||
label-align="left"
|
||||
labelAlign="right"
|
||||
:labelCol="{ span: 4 }"
|
||||
:wrapperCol="{ span: 20 }"
|
||||
>
|
||||
<a-form-item required field="mobile" label="新手机号">
|
||||
<a-input v-model.trim="form.mobile" size="small" placeholder="请输入新的手机号" />
|
||||
</a-form-item>
|
||||
<a-form-item required field="captcha" label="获取验证码">
|
||||
<a-input v-model.trim="form.captcha" size="small" placeholder="请输入验证码">
|
||||
<FormItem required name="mobile" label="新手机号">
|
||||
<Input v-model:value="form.mobile" size="small" placeholder="请输入新的手机号" />
|
||||
</FormItem>
|
||||
<FormItem required name="captcha" label="获取验证码">
|
||||
<Input v-model:value="form.captcha" size="small" placeholder="请输入验证码">
|
||||
<template #suffix>
|
||||
<span v-if="countdown <= 0" @click="sendCaptcha">发送验证码</span>
|
||||
<span v-else>{{ countdown }}s</span>
|
||||
</template>
|
||||
</a-input>
|
||||
</a-form-item>
|
||||
</a-form>
|
||||
</Input>
|
||||
</FormItem>
|
||||
</Form>
|
||||
<PuzzleVerification
|
||||
:show="verificationVisible"
|
||||
@submit="handleVerificationSubmit"
|
||||
@ -78,6 +83,7 @@
|
||||
</div>
|
||||
</template>
|
||||
<script setup lang="ts">
|
||||
import { Button, Form, FormItem, Input, Table, message, Avatar } from 'ant-design-vue';
|
||||
import Container from '@/components/container.vue';
|
||||
import Modal from '@/components/modal.vue';
|
||||
import PuzzleVerification from '@/views/login/components/PuzzleVerification.vue';
|
||||
@ -122,35 +128,32 @@ const dataSource = computed(() => {
|
||||
const formRules = {
|
||||
mobile: [
|
||||
{
|
||||
required: true,
|
||||
message: '请填写手机号',
|
||||
trigger: ['blur', 'change'],
|
||||
},
|
||||
{
|
||||
validator: (value: string, callback: (error?: string) => void) => {
|
||||
if (!/^1[3-9]\d{9}$/.test(value)) {
|
||||
callback('手机号格式不正确');
|
||||
} else {
|
||||
callback();
|
||||
validator: (_rule: any, value: string) => {
|
||||
if (!value) {
|
||||
return Promise.reject('请填写手机号');
|
||||
}
|
||||
if (!/^1[3-9]\d{9}$/.test(value)) {
|
||||
return Promise.reject('手机号格式不正确');
|
||||
}
|
||||
return Promise.resolve();
|
||||
},
|
||||
required: true,
|
||||
trigger: ['blur', 'change'],
|
||||
},
|
||||
],
|
||||
captcha: [
|
||||
{
|
||||
required: true,
|
||||
message: '请填写验证码',
|
||||
trigger: ['blur', 'change'],
|
||||
},
|
||||
{
|
||||
validator: (value: string, callback: (error?: string) => void) => {
|
||||
if (!/^\d{6}$/.test(value)) {
|
||||
callback('验证码必须是6位数字');
|
||||
} else {
|
||||
callback();
|
||||
validator: (rule, value) => {
|
||||
if (!value) {
|
||||
return Promise.reject('请填写验证码');
|
||||
}
|
||||
if (!/^\d{6}$/.test(value)) {
|
||||
return Promise.reject('验证码必须是6位数字');
|
||||
}
|
||||
return Promise.resolve();
|
||||
},
|
||||
|
||||
trigger: ['blur', 'change'],
|
||||
},
|
||||
],
|
||||
@ -203,7 +206,7 @@ function openEditMobileModal() {
|
||||
|
||||
async function handleSubmitUserInfo() {
|
||||
await updateMyInfo(userInfoForm);
|
||||
AMessage.success('修改成功!');
|
||||
message.success('修改成功!');
|
||||
}
|
||||
|
||||
async function sendCaptcha() {
|
||||
@ -213,7 +216,7 @@ async function sendCaptcha() {
|
||||
verificationVisible.value = true;
|
||||
isSendCaptcha.value = true;
|
||||
}
|
||||
AMessage.error('请填写正确的手机号!');
|
||||
message.error('请填写正确的手机号!');
|
||||
} catch (error) {
|
||||
console.log('手机号验证失败:', error);
|
||||
}
|
||||
@ -231,7 +234,7 @@ function beginCountdown() {
|
||||
|
||||
async function handleVerificationSubmit() {
|
||||
await sendUpdateMobileCaptcha({ mobile: form.mobile });
|
||||
AMessage.success('发送成功');
|
||||
message.success('发送成功');
|
||||
verificationVisible.value = false;
|
||||
countdown.value = 60;
|
||||
beginCountdown();
|
||||
@ -239,13 +242,13 @@ async function handleVerificationSubmit() {
|
||||
|
||||
async function handleUpdateMobile() {
|
||||
if (!isSendCaptcha.value) {
|
||||
AMessage.error('请先获取验证码!');
|
||||
message.error('请先获取验证码!');
|
||||
return false;
|
||||
}
|
||||
const res = await formRef.value.validate();
|
||||
if (res === true || res === undefined) {
|
||||
await updateMobile(form);
|
||||
AMessage.success('修改成功!');
|
||||
message.success('修改成功!');
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -1,34 +0,0 @@
|
||||
<!--
|
||||
* @Author: 田鑫
|
||||
* @Date: 2023-03-05 15:13:44
|
||||
* @LastEditors: 田鑫
|
||||
* @LastEditTime: 2023-03-05 15:43:18
|
||||
* @Description: 模拟登录鉴权页
|
||||
-->
|
||||
|
||||
<template>
|
||||
<a-modal title="登录鉴权页" :visible="true" :footer="false">
|
||||
<div w100 align-center>
|
||||
<a-button w-160 @click="login" :loading="loading" type="primary">登录</a-button>
|
||||
</div>
|
||||
</a-modal>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
const route = useRoute();
|
||||
const router = useRouter();
|
||||
const loading = ref(false);
|
||||
|
||||
function login() {
|
||||
loading.value = true;
|
||||
localStorage.setItem('satoken', '123asdzxc');
|
||||
AMessage.success('登录鉴权成功,准备跳转');
|
||||
setTimeout(() => {
|
||||
loading.value = false;
|
||||
router.push({ name: route.query?.redirect ? route.query?.redirect : 'dashboard' });
|
||||
}, 1500);
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
</style>
|
||||
@ -1,19 +0,0 @@
|
||||
<!--
|
||||
* @Author: 田鑫
|
||||
* @Date: 2023-03-05 14:27:21
|
||||
* @LastEditors: 田鑫
|
||||
* @LastEditTime: 2023-03-05 15:14:15
|
||||
* @Description:
|
||||
-->
|
||||
<template>
|
||||
<a-modal title="选择企业:" :visible="true">
|
||||
<a-select v-model="enterprise" placeholder="请选择您的企业"></a-select>
|
||||
</a-modal>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
const enterprise = ref('');
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
</style>
|
||||
@ -6,7 +6,7 @@
|
||||
<div class="m-auto mt-24px max-w-1000px">
|
||||
<Container title="推荐产品" class="container-body">
|
||||
<div class="grid grid-cols-3 gap-20px">
|
||||
<Product v-for="product in products" :key="product.id" :product="product" @refresh="getProductList" />
|
||||
<!-- <Product v-for="product in products" :key="product.id" :product="product" @refresh="getProductList" /> -->
|
||||
</div>
|
||||
<NoData v-if="products.length === 0" />
|
||||
</Container>
|
||||
@ -20,7 +20,7 @@
|
||||
</template>
|
||||
<script setup lang="ts">
|
||||
import Container from '@/components/container.vue';
|
||||
import Product from '@/views/components/workplace/modules/product.vue';
|
||||
// import Product from '@/views/components/workplace/modules/product.vue';
|
||||
import Case from '@/views/components/workplace/modules/case.vue';
|
||||
import { fetchProductList, fetchSuccessCaseList } from '@/api/all/index';
|
||||
import { ref, onMounted } from 'vue';
|
||||
|
||||
@ -2,16 +2,15 @@
|
||||
<div class="container">
|
||||
<div class="flex arco-row-justify-space-between">
|
||||
<img class="avatar" :src="props.product.image" :alt="props.product.name" />
|
||||
<a-tag v-if="props.product.status === Status.Enable" class="status status-enable">已开通</a-tag>
|
||||
<a-tag v-if="props.product.status === Status.Disable" class="status status-disable">未开通</a-tag>
|
||||
<a-tag v-if="props.product.status === Status.EXPIRED" class="status status-expired">已到期</a-tag>
|
||||
<a-tag v-if="props.product.status === Status.TRIAL_ENDS" class="status status-expired">试用结束</a-tag>
|
||||
<a-countdown
|
||||
<Tag v-if="props.product.status === Status.Enable" class="status status-enable">已开通</Tag>
|
||||
<Tag v-if="props.product.status === Status.Disable" class="status status-disable">未开通</Tag>
|
||||
<Tag v-if="props.product.status === Status.EXPIRED" class="status status-expired">已到期</Tag>
|
||||
<Tag v-if="props.product.status === Status.TRIAL_ENDS" class="status status-expired">试用结束</Tag>
|
||||
<Countdown
|
||||
v-if="props.product.status === Status.ON_TRIAL"
|
||||
class="status-on-trill"
|
||||
title="试用中"
|
||||
:value="1000 * (props.product.expired_at ?? 0)"
|
||||
:now="now()"
|
||||
format="D天H时m分s秒"
|
||||
/>
|
||||
</div>
|
||||
@ -22,47 +21,50 @@
|
||||
</p>
|
||||
</div>
|
||||
<div class="footer flex arco-row-justify-start">
|
||||
<a-button
|
||||
<Button
|
||||
v-if="props.product.status === Status.Enable || props.product.status === Status.ON_TRIAL"
|
||||
type="primary"
|
||||
size="mini"
|
||||
size="small"
|
||||
class="mr-8px"
|
||||
@click="gotoModule(props.product.id)"
|
||||
>
|
||||
进入模块
|
||||
</a-button>
|
||||
<a-button
|
||||
</Button>
|
||||
<Button
|
||||
v-if="props.product.status === Status.TRIAL_ENDS || props.product.status === Status.EXPIRED"
|
||||
size="mini"
|
||||
size="small"
|
||||
type="primary"
|
||||
class="mr-8px"
|
||||
@click="visible = true"
|
||||
>
|
||||
立即购买
|
||||
</a-button>
|
||||
<a-button
|
||||
</Button>
|
||||
<Button
|
||||
v-if="props.product.status === Status.ON_TRIAL"
|
||||
class="mr-8px"
|
||||
size="mini"
|
||||
type="outline"
|
||||
size="small"
|
||||
type="primary"
|
||||
ghost
|
||||
@click="visible = true"
|
||||
>
|
||||
升级购买
|
||||
</a-button>
|
||||
<a-button
|
||||
</Button>
|
||||
<Button
|
||||
v-if="props.product.status === Status.TRIAL_ENDS || props.product.status === Status.EXPIRED"
|
||||
class="mr-8px"
|
||||
size="mini"
|
||||
type="outline"
|
||||
size="small"
|
||||
type="primary"
|
||||
ghost
|
||||
@click="visible = true"
|
||||
>
|
||||
联系客服
|
||||
</a-button>
|
||||
<a-popconfirm focusLock title="试用产品" content="确定试用该产品吗?" @ok="handleTrial(props.product.id)">
|
||||
<a-button v-if="props.product.status === Status.Disable" size="mini" type="outline"> 免费试用7天 </a-button>
|
||||
</a-popconfirm>
|
||||
</Button>
|
||||
<Popconfirm title="试用产品" ok-text="确定" cancel-text="取消" @confirm="handleTrial(props.product.id)">
|
||||
<template #description>确定试用该产品吗?</template>
|
||||
<Button v-if="props.product.status === Status.Disable" size="small" type="default" ghost> 免费试用7天 </Button>
|
||||
</Popconfirm>
|
||||
</div>
|
||||
<CustomerServiceModal v-model:visible="visible" />
|
||||
<CustomerServiceModal v-model:open="visible" centered/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@ -71,6 +73,8 @@ import { now } from '@vueuse/core';
|
||||
import { trialProduct } from '@/api/all';
|
||||
import { useRouter } from 'vue-router';
|
||||
import CustomerServiceModal from '@/components/customer-service-modal.vue';
|
||||
import { Button, message, Tag, Statistic, Popconfirm } from 'ant-design-vue';
|
||||
const { Countdown } = Statistic;
|
||||
|
||||
import { useSidebarStore } from '@/stores/modules/side-bar';
|
||||
import { useEnterpriseStore } from '@/stores/modules/enterprise';
|
||||
@ -110,7 +114,7 @@ const handleTrial = async (id: any) => {
|
||||
if (code === 200) {
|
||||
getUserEnterpriseInfo();
|
||||
|
||||
AMessage.success('试用成功!');
|
||||
message.success('试用成功!');
|
||||
emit('refresh');
|
||||
}
|
||||
};
|
||||
@ -174,7 +178,7 @@ const gotoModule = (menuId: number) => {
|
||||
border-radius: 4px;
|
||||
background: rgba(255, 245, 222, 1);
|
||||
|
||||
:deep(.arco-statistic-title) {
|
||||
:deep(.ant-statistic-title) {
|
||||
font-family: $font-family-medium;
|
||||
font-weight: 400;
|
||||
font-size: 12px;
|
||||
@ -184,7 +188,7 @@ const gotoModule = (menuId: number) => {
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
:deep(.arco-statistic-value) {
|
||||
:deep(.ant-statistic-content) {
|
||||
font-family: $font-family-medium;
|
||||
font-weight: 400;
|
||||
font-size: 10px;
|
||||
|
||||
Reference in New Issue
Block a user