Merge remote-tracking branch 'origin/feature/0902_antd组件替换' into test
# Conflicts: # src/App.vue # src/components/common-select/index.vue # src/layouts/components/navbar/components/task-center-modal/components/import-task/index.vue # src/views/components/login/index.vue # src/views/home/components/history-conversation-drawer/index.vue # src/views/login/style.scss # src/views/property-marketing/media-account/account-manage/components/add-account-modal/index.vue
This commit is contained in:
@ -7,9 +7,9 @@
|
||||
</div>
|
||||
<div class="info-section">
|
||||
<div class="title-group">
|
||||
<a-tooltip :content="cozeInfo.name">
|
||||
<Tooltip :title="cozeInfo.name">
|
||||
<div class="title">{{ cozeInfo.name }}</div>
|
||||
</a-tooltip>
|
||||
</Tooltip>
|
||||
<div class="tag">
|
||||
<div>
|
||||
<img class="status-icon" :src="chatbotIcon" />
|
||||
@ -18,12 +18,8 @@
|
||||
</div>
|
||||
</div>
|
||||
<div class="usage-info">
|
||||
<a-space>
|
||||
<span class="count">{{ cozeInfo.views }}</span>
|
||||
</a-space>
|
||||
<a-space>
|
||||
<span class="label"> 次使用 </span>
|
||||
</a-space>
|
||||
<span class="count">{{ cozeInfo.views }}</span>
|
||||
<span class="label"> 次使用 </span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="description-section">
|
||||
@ -36,6 +32,7 @@
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { defineProps } from 'vue';
|
||||
import { Tooltip } from 'ant-design-vue';
|
||||
import chatbotIcon from '@/assets/svg/chatbot.svg';
|
||||
|
||||
const props = defineProps({
|
||||
|
||||
@ -36,9 +36,9 @@
|
||||
<div class="body">
|
||||
<div class="">
|
||||
<div class="toggle-btn cursor-pointer" @click="toggleCollapse">
|
||||
<a-tooltip :content="isCollapsed ? '展开' : '折叠'">
|
||||
<Tooltip :title="isCollapsed ? '展开' : '折叠'">
|
||||
<img class="status-icon" :src="isCollapsed ? menuUnfold : menuFold" />
|
||||
</a-tooltip>
|
||||
</Tooltip>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@ -55,6 +55,7 @@ import { getChatAgent } from '@/api/all/agent';
|
||||
import { useRouter } from 'vue-router';
|
||||
import menuFold from '@/assets/svg/menu-fold.svg';
|
||||
import menuUnfold from '@/assets/svg/menu-unfold.svg';
|
||||
import { Tooltip } from 'ant-design-vue';
|
||||
import { formatNumberShow } from '@/utils/tools';
|
||||
|
||||
const router = useRouter();
|
||||
|
||||
@ -1,41 +1,42 @@
|
||||
<template>
|
||||
<div class="agent-wrap relative h-full pl-16px">
|
||||
<a-input
|
||||
v-model="query.name"
|
||||
<Input
|
||||
v-model:value="query.name"
|
||||
@press-enter="getData()"
|
||||
placeholder="搜索智能体"
|
||||
size="large"
|
||||
allow-clear
|
||||
class="absolute right-0 top-4px !w-400px"
|
||||
class="absolute right-0 top-4px !w-400px"
|
||||
>
|
||||
<template #prefix>
|
||||
<icon-search @click="getData()" />
|
||||
</template>
|
||||
</a-input>
|
||||
<div v-for="(item, index) in list" :key="index">
|
||||
</Input>
|
||||
<div v-for="(item, index) in list" :key="index">
|
||||
<p class="span-title w-fit mb-16px">{{ item.name }}</p>
|
||||
<a-row class="grid-demo" :gutter="[20, 16]" v-if="item.agent_products.length > 0">
|
||||
<a-col :xs="24"
|
||||
:sm="12"
|
||||
:md="8"
|
||||
:lg="5"
|
||||
:xl="6"
|
||||
:xxl="4"
|
||||
v-for="(product, k) in item.agent_products" :key="k">
|
||||
<Row class="grid-demo" :gutter="[20, 16]" v-if="item.agent_products.length > 0">
|
||||
<Col :xs="24" :sm="12" :md="8" :lg="5" :xl="6" :xxl="4" v-for="(product, k) in item.agent_products" :key="k">
|
||||
<div class="card-container cursor-pointer !h-252px" @click="goDetail(product?.type, product?.id)">
|
||||
<div class="card-image h-120px w-100% bg-cover bg-center mb-8px" v-image-main-color="product.image_url">
|
||||
<img class="object-contain h-full w-100% " :src="product?.image_url"/>
|
||||
<div class="card-image h-120px w-100% bg-cover bg-center mb-8px" v-image-main-color="product.image_url">
|
||||
<img class="object-contain h-full w-100%" :src="product?.image_url" />
|
||||
</div>
|
||||
|
||||
<div class="card-content w-full">
|
||||
<TextoverTips :context="product.name" class="card-title mb-4px !text-16px"/>
|
||||
<TextoverTips :context="product.description" class="card-description mb-8px color-#737478 text-14px lh-22px font-400" :line="2" />
|
||||
<TextOverTips :context="product.name" class="card-title mb-4px !text-16px" />
|
||||
<TextOverTips
|
||||
:context="product.description"
|
||||
class="card-description mb-8px color-#737478 text-14px lh-22px font-400"
|
||||
:line="2"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div class="card-footer">
|
||||
<div
|
||||
:class="['status-tag', product.type === 1 ? 'blue-tag' : 'red-tag']"
|
||||
:style="{ background: product.type === 1 ? 'var(--Functional-Blue-1, #F0EDFF)' : 'var(--Functional-Red-1, #FFE9E7)' }"
|
||||
:style="{
|
||||
background:
|
||||
product.type === 1 ? 'var(--Functional-Blue-1, #F0EDFF)' : 'var(--Functional-Red-1, #FFE9E7)',
|
||||
}"
|
||||
data-size="mini-20px"
|
||||
>
|
||||
<SvgIcon
|
||||
@ -48,13 +49,15 @@
|
||||
<div class="status-text">{{ product.type === 1 ? '对话式' : '工作流' }}</div>
|
||||
</div>
|
||||
<div class="usage-info">
|
||||
<div class="usage-count mr-2px">{{ formatNumberShow({ value: product?.views, showExactValue: true }) }}</div>
|
||||
<div class="usage-count mr-2px">
|
||||
{{ formatNumberShow({ value: product?.views, showExactValue: true }) }}
|
||||
</div>
|
||||
<div class="usage-label">次使用</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</a-col>
|
||||
</a-row>
|
||||
</Col>
|
||||
</Row>
|
||||
|
||||
<NoData v-else />
|
||||
</div>
|
||||
@ -62,10 +65,11 @@
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { Input, Row, Col } from 'ant-design-vue';
|
||||
import { useRouter } from 'vue-router';
|
||||
import { getAgentList } from '@/api/all/agent';
|
||||
import { formatNumberShow } from "@/utils/tools";
|
||||
import TextoverTips from "@/components/text-over-tips";
|
||||
import { formatNumberShow } from '@/utils/tools';
|
||||
import TextOverTips from '@/components/text-over-tips';
|
||||
|
||||
const router = useRouter();
|
||||
|
||||
|
||||
@ -1,29 +1,26 @@
|
||||
<template>
|
||||
<div class="form-container">
|
||||
<a-form :model="formData" ref="formRef" layout="vertical">
|
||||
<a-form-item
|
||||
<Form :model="formData" ref="formRef" layout="vertical">
|
||||
<FormItem
|
||||
v-for="(field, index) in formFields"
|
||||
:key="index"
|
||||
:label="field.props.label"
|
||||
:field="field.props.name"
|
||||
:name="field.props.name"
|
||||
:rules="field.props.rules"
|
||||
:tooltip="field.props.tip"
|
||||
>
|
||||
<a-input
|
||||
<Input
|
||||
allowClear
|
||||
v-if="field.type === 'input'"
|
||||
v-model="formData[field.props.name]"
|
||||
v-model:value="formData[field.props.name]"
|
||||
:placeholder="field?.props?.placeholder"
|
||||
/>
|
||||
<a-textarea
|
||||
<TextArea
|
||||
v-if="field.type === 'textarea'"
|
||||
style="width: 500px; height: 200px"
|
||||
v-model="formData[field.props.name]"
|
||||
v-model:value="formData[field.props.name]"
|
||||
:placeholder="field?.props?.placeholder"
|
||||
/>
|
||||
<!-- <a-color-picker v-if="field.type === 'color_picker'"
|
||||
style="width: 500px; height: 200px"
|
||||
v-model="formData[field.props.name]" /> -->
|
||||
<ImageUpload
|
||||
v-if="field.type == 'upload_image'"
|
||||
v-model="formData[field.props.name]"
|
||||
@ -34,24 +31,28 @@
|
||||
v-model="formData[field.props.name]"
|
||||
:limit="field.props.limit"
|
||||
></FileUpload>
|
||||
<a-select
|
||||
<Select
|
||||
v-else-if="field.type === 'select'"
|
||||
v-model="formData[field.props.name]"
|
||||
v-model:value="formData[field.props.name]"
|
||||
:placeholder="field.placeholder"
|
||||
>
|
||||
<a-option v-for="(option, optIndex) in field.props.options" :key="optIndex" :value="option.value">
|
||||
<Option v-for="(option, optIndex) in field.props.options" :key="optIndex" :value="option.value">
|
||||
{{ option.label }}
|
||||
</a-option>
|
||||
</a-select>
|
||||
</a-form-item>
|
||||
</a-form>
|
||||
<a-button class="submit-btn" type="primary" :disabled="loading" @click="handleSubmit">提交执行</a-button>
|
||||
</Option>
|
||||
</Select>
|
||||
</FormItem>
|
||||
</Form>
|
||||
<Button class="submit-btn" type="primary" :disabled="loading" @click="handleSubmit">提交执行</Button>
|
||||
</div>
|
||||
</template>
|
||||
<script setup>
|
||||
import { defineProps, defineEmits } from 'vue';
|
||||
import ImageUpload from '@/components/upload/ImageUpload.vue';
|
||||
import FileUpload from '@/components/upload/FileUpload.vue';
|
||||
import { Button, Input, Select, Row, Col, Form } from 'ant-design-vue';
|
||||
const { TextArea } = Input;
|
||||
const { Option } = Select;
|
||||
const { Item: FormItem } = Form;
|
||||
|
||||
const props = defineProps({
|
||||
formFields: {
|
||||
@ -79,24 +80,25 @@ const handleSubmit = async () => {
|
||||
|
||||
<style scoped lang="scss">
|
||||
.form-container {
|
||||
:deep(.arco-input-wrapper),
|
||||
:deep(.arco-textarea-wrapper) {
|
||||
:deep(.ant-input),
|
||||
:deep(.ant-input:focus),
|
||||
:deep(.ant-input-focused) {
|
||||
border-radius: 4px;
|
||||
border-color: #d7d7d9;
|
||||
background-color: #fff;
|
||||
height: 35px;
|
||||
width: 300px;
|
||||
|
||||
&:focus-within,
|
||||
&.arco-input-focus {
|
||||
&:focus,
|
||||
&:focus-within {
|
||||
background-color: var(--color-bg-2);
|
||||
border-color: rgb(var(--primary-6));
|
||||
box-shadow: 0 0 0 0 var(--color-primary-light-2);
|
||||
}
|
||||
}
|
||||
|
||||
&.arco-textarea-wrapper {
|
||||
height: 60px;
|
||||
}
|
||||
&.ant-textarea-wrapper {
|
||||
height: 60px;
|
||||
}
|
||||
|
||||
.submit-btn {
|
||||
|
||||
@ -42,15 +42,14 @@
|
||||
{{ item.title }}
|
||||
</div>
|
||||
<div class="trigger-container">
|
||||
<a-trigger
|
||||
mouse-leave-delay="200"
|
||||
position="top"
|
||||
<Dropdown
|
||||
:mouseLeaveDelay="200"
|
||||
placement="top"
|
||||
trigger="hover"
|
||||
:auto-fit-position="false"
|
||||
:unmount-on-close="true"
|
||||
:overlayStyle="{ width: 'auto' }"
|
||||
>
|
||||
<SvgIcon size="12" name="svg-more" class="icon-more" />
|
||||
<template #content>
|
||||
<template #overlay>
|
||||
<div class="">
|
||||
<div class="history-item-dropdown">
|
||||
<div class="dropdown-item">
|
||||
@ -61,18 +60,19 @@
|
||||
</div>
|
||||
<div class="dropdown-item">
|
||||
<SvgIcon size="12" name="svg-delete" class="icon color-#6D4CFE" />
|
||||
<a-popconfirm
|
||||
<Popconfirm
|
||||
content="你确认删除该历史对话吗"
|
||||
@ok="deleteHistory(item.id, index)"
|
||||
type="error"
|
||||
@confirm="deleteHistory(item.id, index)"
|
||||
ok-text="确定"
|
||||
cancel-text="取消"
|
||||
>
|
||||
<div class="text delete">删除</div>
|
||||
</a-popconfirm>
|
||||
</Popconfirm>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
</a-trigger>
|
||||
</Dropdown>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@ -83,9 +83,9 @@
|
||||
<div class="body">
|
||||
<div class="">
|
||||
<div class="toggle-btn cursor-pointer" @click="toggleCollapse">
|
||||
<a-tooltip :content="isCollapsed ? '展开' : '折叠'">
|
||||
<Tooltip :title="isCollapsed ? '展开' : '折叠'">
|
||||
<img class="status-icon" :src="isCollapsed ? menuUnfold : menuFold" />
|
||||
</a-tooltip>
|
||||
</Tooltip>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@ -95,7 +95,7 @@
|
||||
<DynamicForm :formFields="formFields.form" :formData="formData" :loading="loading" @submit="handleSubmit" />
|
||||
</div>
|
||||
<div class="res h-full">
|
||||
<a-spin v-if="loading" class="spin-center" tip="生成中。。。" />
|
||||
<Spin v-if="loading" wrapperClassName="spin-center" tip="生成中。。。" />
|
||||
<div
|
||||
class="markdown-container"
|
||||
v-if="workFlowRes.output != '' && loading === false"
|
||||
@ -107,15 +107,16 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<a-modal style="width: 500px" v-model:visible="editHistoryVisible">
|
||||
<Modal style="width: 500px" v-model:open="editHistoryVisible" centered>
|
||||
<template #title> Title</template>
|
||||
<div></div>
|
||||
</a-modal>
|
||||
</Modal>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref, reactive } from 'vue';
|
||||
import { Modal, Tooltip, message, Popconfirm, Spin, Dropdown } from 'ant-design-vue';
|
||||
import DynamicForm from './components/DynamicForm.vue';
|
||||
import {
|
||||
executeWorkFlow,
|
||||
@ -214,17 +215,17 @@ const handleTop = async (id, sort, event) => {
|
||||
|
||||
//置顶
|
||||
const topHistory = async (id, sort) => {
|
||||
const { code, message } = await topWorkflowHistoryApi(id);
|
||||
const { code, message: msg } = await topWorkflowHistoryApi(id);
|
||||
if (code === 200) {
|
||||
AMessage.success(message);
|
||||
message.success(msg);
|
||||
getWorkflowHistoryList();
|
||||
}
|
||||
};
|
||||
//取消置顶
|
||||
const canceltopHistory = async (id, sort) => {
|
||||
const { code, message } = await cancelTopWorkflowHistoryApi(id);
|
||||
const { code, message: msg } = await cancelTopWorkflowHistoryApi(id);
|
||||
if (code === 200) {
|
||||
AMessage.success(message);
|
||||
message.success(msg);
|
||||
getWorkflowHistoryList();
|
||||
}
|
||||
};
|
||||
|
||||
@ -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();
|
||||
|
||||
@ -9,7 +9,7 @@
|
||||
<img src="@/assets/img/Frame.svg" class="w-480 h-480 mr-40" alt="" />
|
||||
</div>
|
||||
<div class="flex items-center w-400 h-100%">
|
||||
<a-space
|
||||
<Space
|
||||
direction="vertical"
|
||||
size="large"
|
||||
align="center"
|
||||
@ -17,30 +17,27 @@
|
||||
>
|
||||
<img src="@/assets/img/icon-logo.png" alt="" width="96" height="24" class="mb-8px" />
|
||||
<span class="text-4 color-#737478">AI营销工具</span>
|
||||
<a-form ref="formRef" :model="loginForm" :rules="formRules" auto-label-width class="w-320 mt-48px form-wrap">
|
||||
<a-form-item field="mobile" hide-label>
|
||||
<a-input
|
||||
v-model="loginForm.mobile"
|
||||
<Form ref="formRef" :model="loginForm" :rules="formRules" auto-label-width class="w-320 mt-48px form-wrap">
|
||||
<FormItem name="mobile">
|
||||
<Input
|
||||
v-model:value="loginForm.mobile"
|
||||
placeholder="输入手机号"
|
||||
class="form-input border border-solid border-#d7d7d9 x w-100% h-48px text-14 rounded-4px color-#333 bg-#fff"
|
||||
class="form-input border border-solid !border-#d7d7d9 w-100% h-48px !text-14px rounded-4px color-#333 bg-#fff"
|
||||
clearable
|
||||
allow-clear
|
||||
@blur="validateField('mobile')"
|
||||
@input="clearError('mobile')"
|
||||
allowClear
|
||||
/>
|
||||
</a-form-item>
|
||||
<a-form-item field="captcha" hide-label>
|
||||
</FormItem>
|
||||
<FormItem name="captcha">
|
||||
<div
|
||||
class="form-input border border-solid border-#d7d7d9 w-100% h-48px text-14 rounded-4px color-#333 bg-#fff flex justify-between items-center"
|
||||
class="form-input border border-solid !border-#d7d7d9 w-100% h-48px !text-14px rounded-4px color-#333 bg-#fff flex justify-between items-center"
|
||||
>
|
||||
<a-input
|
||||
v-model="loginForm.captcha"
|
||||
<Input
|
||||
v-model:value="loginForm.captcha"
|
||||
placeholder="验证码"
|
||||
style="background-color: #fff; border: none"
|
||||
allow-clear
|
||||
maxlength="6"
|
||||
@blur="validateField('captcha')"
|
||||
@input="clearError('captcha')"
|
||||
style="background-color: #fff; border: none !important;"
|
||||
allowClear
|
||||
class="form-input"
|
||||
:maxlength="6"
|
||||
/>
|
||||
<span
|
||||
class="w-120 font-400 text-right mr-4 text-16px"
|
||||
@ -52,27 +49,27 @@
|
||||
>{{ countdown > 0 ? `${countdown}s` : hasGetCode ? '重新发送' : '发送验证码' }}</span
|
||||
>
|
||||
</div>
|
||||
</a-form-item>
|
||||
<a-form-item hide-label class="mt-68px mb-16px">
|
||||
<a-button
|
||||
</FormItem>
|
||||
<FormItem class="mt-68px mb-16px">
|
||||
<Button
|
||||
type="primary"
|
||||
class="w-480 h-48 !text-16px !rounded-8px"
|
||||
class="w-full h-48 !text-16px !rounded-8px"
|
||||
:class="disabledSubmitBtn ? 'cursor-no-drop' : 'cursor-pointer'"
|
||||
:disabled="disabledSubmitBtn"
|
||||
@click="handleSubmit"
|
||||
>
|
||||
{{ isLogin ? '登录' : '注册并开通企业账号' }}
|
||||
</a-button>
|
||||
</a-form-item>
|
||||
</a-form>
|
||||
<a-space class="text-12px color-#737478 justify-start items-center">
|
||||
<a-checkbox v-model="hasCheck" class="!text-12px mr-8px"></a-checkbox>
|
||||
</Button>
|
||||
</FormItem>
|
||||
</Form>
|
||||
<Space class="text-12px color-#737478 justify-start items-center">
|
||||
<Checkbox v-model:checked="hasCheck" class="!text-12px mr-8px"></Checkbox>
|
||||
<span class="text-12px color-#737478">{{ isLogin ? '登录' : '注册' }}即代表同意</span>
|
||||
<a-link href="link" class="form-link color-#211F24" target="_blank">用户协议</a-link>
|
||||
<Link href="link" class="form-link color-#211F24" target="_blank">用户协议</Link>
|
||||
<span class="text-12px color-#737478">和</span>
|
||||
<a-link href="link" class="form-link color-#211f24" target="_blank">隐私政策</a-link>
|
||||
</a-space>
|
||||
</a-space>
|
||||
<Link href="link" class="form-link color-#211f24" target="_blank">隐私政策</Link>
|
||||
</Space>
|
||||
</Space>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
@ -85,18 +82,18 @@
|
||||
@submit="handleVerificationSubmit"
|
||||
@cancel="isVerificationVisible = false"
|
||||
/>
|
||||
<a-modal :visible="visible" unmountOnClose hide-cancel @ok="handleOk" @cancel="handleCancel">
|
||||
<Modal v-model:open="visible" centered unmountOnClose @cancel="handleCancel">
|
||||
<template #title>
|
||||
<span style="text-align: left; width: 100%">选择账号</span>
|
||||
</template>
|
||||
<div class="account-bind-container">
|
||||
<a-card :bordered="false" class="bind-card">
|
||||
<Card :bordered="false" class="bind-card">
|
||||
<div class="bind-header">
|
||||
<a-typography-text class="mobile-number">{{ mobileNumber }} 已在以下企业绑定了账号</a-typography-text>
|
||||
<Typography.Text class="mobile-number">{{ mobileNumber }} 已在以下企业绑定了账号</Typography.Text>
|
||||
</div>
|
||||
|
||||
<a-list :bordered="false" :split="false" class="account-list">
|
||||
<a-list-item
|
||||
<List :bordered="false" :split="false" class="account-list">
|
||||
<List.Item
|
||||
v-for="(account, index) in accounts"
|
||||
:key="index"
|
||||
class="account-item"
|
||||
@ -107,22 +104,29 @@
|
||||
}"
|
||||
@click="selectAccount(account, index)"
|
||||
>
|
||||
<a-list-item-meta>
|
||||
<List.Item.Meta>
|
||||
<template #title>
|
||||
<div style="display: flex; align-items: center; gap: 12px">
|
||||
<a-checkbox :model-value="selectedAccountIndex === index" />
|
||||
<a-typography-text>{{ account.name || '-' }}</a-typography-text>
|
||||
<Checkbox :checked="selectedAccountIndex === index" />
|
||||
<Typography.Text>{{ account.name || '-' }}</Typography.Text>
|
||||
</div>
|
||||
</template>
|
||||
</a-list-item-meta>
|
||||
</a-list-item>
|
||||
</a-list>
|
||||
</a-card>
|
||||
</List.Item.Meta>
|
||||
</List.Item>
|
||||
</List>
|
||||
</Card>
|
||||
</div>
|
||||
</a-modal>
|
||||
<template #footer>
|
||||
<div class="flex">
|
||||
<Button type="primary" @click="handleOk">确定</Button>
|
||||
</div>
|
||||
</template>
|
||||
</Modal>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { Checkbox, Modal, Button, Form, FormItem, Input, Space, message, Typography, Card, List } from 'ant-design-vue';
|
||||
const { Link } = Typography;
|
||||
import PuzzleVerification from './components/PuzzleVerification.vue';
|
||||
import { fetchLoginCaptCha, fetchAuthorizationsCaptcha, fetchProfileInfo } from '@/api/all/login';
|
||||
import { joinEnterpriseByInviteCode } from '@/api/all';
|
||||
@ -159,15 +163,14 @@ const formRules = {
|
||||
mobile: [
|
||||
{
|
||||
required: true,
|
||||
message: '请填写手机号',
|
||||
trigger: ['blur', 'change'],
|
||||
},
|
||||
{
|
||||
validator: (value: string, callback: (error?: string) => void) => {
|
||||
validator: (_rule: any, value: string) => {
|
||||
if (!value) {
|
||||
return Promise.reject('请填写手机号');
|
||||
}
|
||||
if (!/^1[3-9]\d{9}$/.test(value)) {
|
||||
callback('手机号格式不正确');
|
||||
return Promise.reject('手机号格式不正确');
|
||||
} else {
|
||||
callback();
|
||||
return Promise.resolve();
|
||||
}
|
||||
},
|
||||
trigger: ['blur', 'change'],
|
||||
@ -176,15 +179,14 @@ const formRules = {
|
||||
captcha: [
|
||||
{
|
||||
required: true,
|
||||
message: '请填写验证码',
|
||||
trigger: ['blur', 'change'],
|
||||
},
|
||||
{
|
||||
validator: (value: string, callback: (error?: string) => void) => {
|
||||
validator: (_rule: any, value: string) => {
|
||||
if (!value) {
|
||||
return Promise.reject('请填写验证码');
|
||||
}
|
||||
if (!/^\d{6}$/.test(value)) {
|
||||
callback('验证码必须是6位数字');
|
||||
return Promise.reject('验证码必须是6位数字');
|
||||
} else {
|
||||
callback();
|
||||
return Promise.resolve();
|
||||
}
|
||||
},
|
||||
trigger: ['blur', 'change'],
|
||||
@ -216,7 +218,7 @@ const selectAccount = (account: any, index: any) => {
|
||||
};
|
||||
|
||||
const validateField = (field: string) => {
|
||||
formRef.value.validateField(field);
|
||||
formRef.value.validateFields(field);
|
||||
};
|
||||
|
||||
const clearError = (field: string) => {
|
||||
@ -239,11 +241,9 @@ const getCode = async () => {
|
||||
// 先重置验证状态
|
||||
formRef.value.clearValidate('mobile');
|
||||
|
||||
const result = await formRef.value.validateField('mobile');
|
||||
// 只有当验证通过时才会显示滑块验证
|
||||
if (result === true || result === undefined) {
|
||||
formRef.value.validateFields('mobile').then(() => {
|
||||
isVerificationVisible.value = true;
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
// 验证码验证通过后
|
||||
@ -252,9 +252,9 @@ const handleVerificationSubmit = async () => {
|
||||
startCountdown();
|
||||
|
||||
try {
|
||||
const { code, message } = await fetchLoginCaptCha({ mobile: loginForm.mobile });
|
||||
const { code, message: msg } = await fetchLoginCaptCha({ mobile: loginForm.mobile });
|
||||
if (code === 200) {
|
||||
AMessage.success(message);
|
||||
message.success(msg);
|
||||
}
|
||||
} catch (error) {
|
||||
// 重置倒计时
|
||||
@ -292,7 +292,7 @@ const handleSubmit = async () => {
|
||||
await formRef.value.validate();
|
||||
|
||||
if (!hasCheck.value) {
|
||||
AMessage.error('请先勾选同意用户协议');
|
||||
message.error('请先勾选同意用户协议');
|
||||
return;
|
||||
}
|
||||
|
||||
@ -301,14 +301,14 @@ const handleSubmit = async () => {
|
||||
|
||||
if (code === 200) {
|
||||
// 处理登录成功逻辑
|
||||
AMessage.success(isLogin.value ? '登录成功' : '注册成功');
|
||||
message.success(isLogin.value ? '登录成功' : '注册成功');
|
||||
userStore.setToken(data.access_token);
|
||||
|
||||
const { invite_code } = route.query;
|
||||
if (invite_code) {
|
||||
const { code } = await joinEnterpriseByInviteCode(invite_code as string);
|
||||
if (code === 200) {
|
||||
AMessage.success('加入企业成功');
|
||||
message.success('加入企业成功');
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -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>
|
||||
|
||||
|
||||
@ -3,32 +3,37 @@
|
||||
<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 }">
|
||||
<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"
|
||||
@ -37,40 +42,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"
|
||||
@ -80,6 +85,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';
|
||||
@ -124,35 +130,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'],
|
||||
},
|
||||
],
|
||||
@ -205,7 +208,7 @@ function openEditMobileModal() {
|
||||
|
||||
async function handleSubmitUserInfo() {
|
||||
await updateMyInfo(userInfoForm);
|
||||
AMessage.success('修改成功!');
|
||||
message.success('修改成功!');
|
||||
}
|
||||
|
||||
async function sendCaptcha() {
|
||||
@ -215,7 +218,7 @@ async function sendCaptcha() {
|
||||
verificationVisible.value = true;
|
||||
isSendCaptcha.value = true;
|
||||
}
|
||||
AMessage.error('请填写正确的手机号!');
|
||||
message.error('请填写正确的手机号!');
|
||||
} catch (error) {
|
||||
console.log('手机号验证失败:', error);
|
||||
}
|
||||
@ -233,7 +236,7 @@ function beginCountdown() {
|
||||
|
||||
async function handleVerificationSubmit() {
|
||||
await sendUpdateMobileCaptcha({ mobile: form.mobile });
|
||||
AMessage.success('发送成功');
|
||||
message.success('发送成功');
|
||||
verificationVisible.value = false;
|
||||
countdown.value = 60;
|
||||
beginCountdown();
|
||||
@ -241,13 +244,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;
|
||||
|
||||
@ -1,20 +1,19 @@
|
||||
<template>
|
||||
<a-modal v-model:visible="visible" title="删除对话" width="400px" @close="onClose">
|
||||
<Modal v-model:open="visible" title="删除对话" width="400px" @cancel="onClose" centered>
|
||||
<div class="flex items-center">
|
||||
<img :src="icon1" width="20" height="20" class="mr-12px" />
|
||||
<span>确认删除对话吗?删除后,聊天记录将不可恢复。</span>
|
||||
</div>
|
||||
<template #footer>
|
||||
<a-button size="large" @click="onClose">取消</a-button>
|
||||
<a-button type="primary" class="ml-16px !bg-#f64b31 !border-none" status="danger" size="large" @click="onDelete"
|
||||
>确定</a-button
|
||||
>
|
||||
<Button @click="onClose">取消</Button>
|
||||
<Button type="primary" danger @click="onDelete">确定</Button>
|
||||
</template>
|
||||
</a-modal>
|
||||
</Modal>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref } from 'vue';
|
||||
import { Modal, Button, message } from 'ant-design-vue';
|
||||
import { deleteHistoryItem } from '@/api/all/chat';
|
||||
import icon1 from '@/assets/img/media-account/icon-warn-1.png';
|
||||
|
||||
@ -41,7 +40,7 @@ const open = (record) => {
|
||||
async function onDelete() {
|
||||
const { code } = await deleteHistoryItem(conversationId.value);
|
||||
if (code === 200) {
|
||||
AMessage.success('删除成功');
|
||||
message.success('删除成功');
|
||||
emits('delete', conversationId.value);
|
||||
onClose();
|
||||
}
|
||||
|
||||
@ -1,18 +1,19 @@
|
||||
<template>
|
||||
<a-modal v-model:visible="visible" title="确定删除评论?" width="400px" @close="onClose">
|
||||
<Modal v-model:open="visible" title="确定删除评论?" width="400px" @cancel="onClose" centered>
|
||||
<div class="flex items-center">
|
||||
<img :src="icon1" width="20" height="20" class="mr-12px" />
|
||||
<span>删除的评论将从对话中消失,但仍在被引用的评论中可见</span>
|
||||
</div>
|
||||
<template #footer>
|
||||
<a-button size="large" @click="onClose">取消</a-button>
|
||||
<a-button type="primary" class="ml-16px !border-none" size="large" @click="onDelete">删除</a-button>
|
||||
<Button @click="onClose">取消</Button>
|
||||
<Button type="primary" danger @click="onDelete">确定</Button>
|
||||
</template>
|
||||
</a-modal>
|
||||
</Modal>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref } from 'vue';
|
||||
import { Modal, Button } from 'ant-design-vue';
|
||||
import icon1 from '@/assets/img/media-account/icon-warn-1.png';
|
||||
|
||||
const emits = defineEmits(['delete', 'close']);
|
||||
|
||||
@ -1,5 +1,6 @@
|
||||
<script lang="jsx">
|
||||
import { Image, Spin, Button, Input, Textarea, Affix } from '@arco-design/web-vue';
|
||||
import { Button, Input, Image } from 'ant-design-vue';
|
||||
const { TextArea } = Input;
|
||||
import TextOverTips from '@/components/text-over-tips';
|
||||
import SvgIcon from '@/components/svg-icon/index.vue';
|
||||
import DeleteCommentModal from './delete-comment-modal.vue';
|
||||
@ -125,23 +126,23 @@ export default {
|
||||
</div>
|
||||
)}
|
||||
|
||||
<Textarea
|
||||
<TextArea
|
||||
ref={textAreaRef}
|
||||
auto-size
|
||||
class={`max-h-220px overflow-y-auto ${isReplay.value ? 'pt-38px' : ''}`}
|
||||
autoSize
|
||||
class={`max-h-220px overflow-y-auto textarea-box ${isReplay.value ? 'pt-38px' : ''}`}
|
||||
size="large"
|
||||
placeholder="输入评论"
|
||||
v-model={comment.value}
|
||||
v-model:value={comment.value}
|
||||
onPressEnter={onComment}
|
||||
/>
|
||||
</div>
|
||||
|
||||
{comment.value && (
|
||||
<div class="flex justify-end mt-12px">
|
||||
<Button type="outline" class="mr-12px rounded-8px" size="medium" onClick={onClearComment}>
|
||||
<Button type="primary" ghost class="cancel-btn mr-12px !rounded-8px" onClick={onClearComment}>
|
||||
取消
|
||||
</Button>
|
||||
<Button type="primary" class="rounded-8px" size="medium" onClick={onComment}>
|
||||
<Button type="primary" class="!rounded-8px" onClick={onComment}>
|
||||
发送
|
||||
</Button>
|
||||
</div>
|
||||
|
||||
@ -19,6 +19,9 @@
|
||||
font-family: $font-family-medium;
|
||||
}
|
||||
}
|
||||
.cancel-btn {
|
||||
background-color: transparent !important;
|
||||
}
|
||||
.ai-text {
|
||||
font-family: $font-family-medium;
|
||||
font-size: 16px;
|
||||
@ -30,7 +33,7 @@
|
||||
-webkit-background-clip: text;
|
||||
-webkit-text-fill-color: transparent;
|
||||
}
|
||||
:deep(.arco-textarea-wrapper) {
|
||||
.textarea-box {
|
||||
min-height: 38px;
|
||||
display: flex;
|
||||
border-color: transparent !important;
|
||||
@ -39,14 +42,11 @@
|
||||
background-color: #fff;
|
||||
color: #211f24 !important;
|
||||
transition: all 0.3s;
|
||||
.arco-textarea-mirror,
|
||||
.arco-textarea {
|
||||
padding: 8px 16px !important;
|
||||
}
|
||||
padding: 8px 16px !important;
|
||||
&:hover {
|
||||
border-color: #6d4cfe !important;
|
||||
}
|
||||
&.arco-textarea-focus {
|
||||
&:focus-within {
|
||||
border-color: #6d4cfe !important;
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,5 +1,6 @@
|
||||
<script lang="jsx">
|
||||
import { Image, Spin, Button } from '@arco-design/web-vue';
|
||||
import { Button } from 'ant-design-vue';
|
||||
import { Spin } from 'ant-design-vue';
|
||||
import AiSuggest from './components/ai-suggest/';
|
||||
|
||||
import { getShareWorksList, getShareWorksDetail, patchShareWorksConfirm } from '@/api/all/generationWorkshop.ts';
|
||||
@ -186,7 +187,7 @@ export default {
|
||||
下一条
|
||||
</Button>
|
||||
)}
|
||||
<Button type="outline" size="large" class="mr-12px" onClick={onBackList}>
|
||||
<Button type="primary" ghost size="large" class="mr-12px" onClick={onBackList}>
|
||||
返回列表
|
||||
</Button>
|
||||
{renderConfirmBtn()}
|
||||
@ -220,7 +221,7 @@ export default {
|
||||
</div>
|
||||
</header>
|
||||
{loading.value ? (
|
||||
<Spin spinning={loading.value} class="flex-1 w-full flex justify-center items-center" size={60} />
|
||||
<Spin spinning={loading.value} wrapperClassName="flex-1 w-full flex justify-center items-center" size="large" />
|
||||
) : (
|
||||
<section class={`page-wrap relative ${isExpand.value ? 'expand' : ''}`}>
|
||||
<div class="fold-box cursor-pointer" onClick={() => (isExpand.value = true)}>
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
<script lang="jsx">
|
||||
import TextOverTips from '@/components/text-over-tips';
|
||||
import { Image, Spin } from '@arco-design/web-vue';
|
||||
import { Image, Spin } from 'ant-design-vue';
|
||||
|
||||
import { exactFormatTime } from '@/utils/tools';
|
||||
import { handleUserHome } from '@/utils/user.ts';
|
||||
@ -52,7 +52,7 @@ export default {
|
||||
</header>
|
||||
<section class="page-wrapper flex justify-center">
|
||||
{loading.value ? (
|
||||
<Spin spinning={loading.value} class="w-full flex justify-center items-center" size={60} />
|
||||
<Spin spinning={loading.value} wrapperClassName="w-full flex justify-center items-center" size="large" />
|
||||
) : (
|
||||
<div class="explore-container">
|
||||
<div class="explore-list-wrap pt-24px pb-28px">
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
<script lang="tsx">
|
||||
import { Tabs, TabPane } from 'ant-design-vue';
|
||||
import { Tabs, TabPane, Button } from 'ant-design-vue';
|
||||
import ManuscriptList from './manuscript/list/index.vue';
|
||||
import ManuscriptCheckList from './manuscript/check-list/index.vue';
|
||||
import ShareManuscriptModal from '@/views/material-center/components/finished-products/manuscript/components/share-manuscript-modal/index.vue';
|
||||
@ -33,17 +33,17 @@ export default defineComponent({
|
||||
v-slots={{
|
||||
rightExtra: () => (
|
||||
<div class="flex items-center">
|
||||
<a-button type="outline" size="medium" onClick={handleShareModal}>
|
||||
<Button type="primary" ghost size="medium" onClick={handleShareModal}>
|
||||
分享内容稿件
|
||||
</a-button>
|
||||
</Button>
|
||||
{showManuscriptList.value && (
|
||||
<a-button
|
||||
<Button
|
||||
type="primary"
|
||||
size="medium"
|
||||
class="ml-12px"
|
||||
onClick={openUploadModal}
|
||||
v-slots={{
|
||||
icon: () => <icon-plus size="16" />,
|
||||
icon: () => <icon-plus size="16" class="mr-8px" />,
|
||||
default: () => '上传内容稿件',
|
||||
}}
|
||||
/>
|
||||
|
||||
@ -8,42 +8,42 @@
|
||||
<div class="filter-row">
|
||||
<div class="filter-row-item">
|
||||
<span class="label">内容稿件标题</span>
|
||||
<a-space size="medium">
|
||||
<a-input
|
||||
v-model="query.title"
|
||||
<Space size="medium">
|
||||
<Input
|
||||
v-model:value="query.title"
|
||||
class="!w-240px"
|
||||
placeholder="请输入内容稿件标题"
|
||||
size="medium"
|
||||
allow-clear
|
||||
allowClear
|
||||
@change="handleSearch"
|
||||
>
|
||||
<template #prefix>
|
||||
<icon-search />
|
||||
</template>
|
||||
</a-input>
|
||||
</a-space>
|
||||
</Input>
|
||||
</Space>
|
||||
</div>
|
||||
<div class="filter-row-item">
|
||||
<span class="label">序号</span>
|
||||
<a-space size="medium">
|
||||
<a-input
|
||||
v-model="query.uid"
|
||||
<Space size="medium">
|
||||
<Input
|
||||
v-model:value="query.uid"
|
||||
class="!w-160px"
|
||||
placeholder="请输入序号"
|
||||
size="medium"
|
||||
allow-clear
|
||||
allowClear
|
||||
@change="handleSearch"
|
||||
>
|
||||
<template #prefix>
|
||||
<icon-search />
|
||||
</template>
|
||||
</a-input>
|
||||
</a-space>
|
||||
</Input>
|
||||
</Space>
|
||||
</div>
|
||||
<div class="filter-row-item" v-if="query.audit_status === AuditStatus.Pending">
|
||||
<span class="label">上传时间</span>
|
||||
<a-range-picker
|
||||
v-model="created_at"
|
||||
<DatePicker.RangePicker
|
||||
v-model:value="created_at"
|
||||
size="medium"
|
||||
allow-clear
|
||||
format="YYYY-MM-DD"
|
||||
@ -54,25 +54,25 @@
|
||||
<template v-if="[AuditStatus.Auditing, AuditStatus.Passed].includes(query.audit_status)">
|
||||
<div class="filter-row-item">
|
||||
<span class="label">审核平台</span>
|
||||
<a-select
|
||||
v-model="query.audit_platform"
|
||||
size="medium"
|
||||
<Select
|
||||
v-model:value="query.audit_platform"
|
||||
size="middle"
|
||||
placeholder="全部"
|
||||
allow-clear
|
||||
allowClear
|
||||
@change="handleSearch"
|
||||
class="!w-160px"
|
||||
>
|
||||
<a-option v-for="(item, index) in PLATFORMS" :key="index" :value="item.value" :label="item.label">{{
|
||||
<Option v-for="(item, index) in PLATFORMS" :key="index" :value="item.value" :label="item.label">{{
|
||||
item.label
|
||||
}}</a-option>
|
||||
</a-select>
|
||||
}}</Option>
|
||||
</Select>
|
||||
</div>
|
||||
<div class="filter-row-item">
|
||||
<span class="label">审核时间</span>
|
||||
<a-range-picker
|
||||
v-model="audit_started_at"
|
||||
<DatePicker.RangePicker
|
||||
v-model:value="audit_started_at"
|
||||
size="medium"
|
||||
allow-clear
|
||||
allowClear
|
||||
format="YYYY-MM-DD"
|
||||
class="!w-280px"
|
||||
@change="(value) => onDateChange(value, 'audit_started_at')"
|
||||
@ -81,27 +81,31 @@
|
||||
</template>
|
||||
|
||||
<div class="filter-row-item">
|
||||
<a-button type="outline" class="mr-12px" size="medium" @click="handleSearch">
|
||||
<Button type="primary" ghost class="mr-12px" size="medium" @click="handleSearch">
|
||||
<template #icon>
|
||||
<icon-search />
|
||||
<icon-search class="mr-8px"/>
|
||||
</template>
|
||||
<template #default>搜索</template>
|
||||
</a-button>
|
||||
<a-button size="medium" @click="handleReset">
|
||||
</Button>
|
||||
<Button size="medium" @click="handleReset">
|
||||
<template #icon>
|
||||
<icon-refresh />
|
||||
<icon-refresh class="mr-8px" />
|
||||
</template>
|
||||
<template #default>重置</template>
|
||||
</a-button>
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { Button, Input, Select, Space, DatePicker } from 'ant-design-vue';
|
||||
const { Option } = Select;
|
||||
import { defineEmits, defineProps } from 'vue';
|
||||
import { PLATFORMS } from '@/views/material-center/components/finished-products/manuscript/check-list/constants';
|
||||
import { AuditStatus } from '@/views/material-center/components/finished-products/constants';
|
||||
import { ref, nextTick } from 'vue';
|
||||
import dayjs from 'dayjs';
|
||||
|
||||
const props = defineProps({
|
||||
query: {
|
||||
@ -110,7 +114,7 @@ const props = defineProps({
|
||||
},
|
||||
});
|
||||
|
||||
const emits = defineEmits('search', 'reset', 'update:query');
|
||||
const emits = defineEmits(['search', 'reset', 'update:query']);
|
||||
const created_at = ref([]);
|
||||
const audit_started_at = ref([]);
|
||||
|
||||
@ -137,6 +141,7 @@ const onDateChange = (value, type) => {
|
||||
|
||||
const handleReset = () => {
|
||||
created_at.value = [];
|
||||
audit_started_at.value = [];
|
||||
emits('reset');
|
||||
};
|
||||
</script>
|
||||
|
||||
@ -1,25 +1,27 @@
|
||||
<template>
|
||||
<a-modal
|
||||
v-model:visible="visible"
|
||||
<Modal
|
||||
v-model:open="visible"
|
||||
title="删除内容稿件"
|
||||
width="480px"
|
||||
@close="onClose"
|
||||
centered
|
||||
@cancel="onClose"
|
||||
>
|
||||
<div class="flex items-center">
|
||||
<img :src="icon1" width="20" height="20" class="mr-12px" />
|
||||
<span>确认删除 {{ projectName }} 这个内容稿件吗?</span>
|
||||
</div>
|
||||
<template #footer>
|
||||
<a-button size="medium" @click="onClose">取消</a-button>
|
||||
<a-button type="primary" class="ml-16px" status="danger" size="medium" @click="onDelete"
|
||||
>确认删除</a-button
|
||||
<Button size="medium" @click="onClose">取消</Button>
|
||||
<Button type="primary" class="ml-16px" danger size="medium" @click="onDelete"
|
||||
>确认删除</Button
|
||||
>
|
||||
</template>
|
||||
</a-modal>
|
||||
</Modal>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref } from 'vue';
|
||||
import { Button, Modal, message } from 'ant-design-vue';
|
||||
import { deleteWork } from '@/api/all/generationWorkshop';
|
||||
import icon1 from '@/assets/img/media-account/icon-warn-1.png';
|
||||
|
||||
@ -48,7 +50,7 @@ const open = (record) => {
|
||||
async function onDelete() {
|
||||
const { code } = await deleteWork(projectId.value);
|
||||
if (code === 200) {
|
||||
AMessage.success('删除成功');
|
||||
message.success('删除成功');
|
||||
update()
|
||||
onClose();
|
||||
}
|
||||
|
||||
@ -1,133 +1,117 @@
|
||||
<template>
|
||||
<a-table
|
||||
<Table
|
||||
ref="tableRef"
|
||||
:data="dataSource"
|
||||
row-key="id"
|
||||
column-resizable
|
||||
:dataSource="dataSource"
|
||||
rowKey="id"
|
||||
:pagination="false"
|
||||
:scroll="{ x: '100%' }"
|
||||
class="flex-1 manuscript-table w-100%"
|
||||
bordered
|
||||
:row-selection="rowSelection"
|
||||
:selected-row-keys="selectedRowKeys"
|
||||
@sorter-change="handleSorterChange"
|
||||
@select="(selectedKeys, rowKeyValue, record) => emits('select', selectedKeys, rowKeyValue, record)"
|
||||
@select-all="(check) => emits('selectAll', check)"
|
||||
:rowSelection="rowSelection"
|
||||
:showSorterTooltip="false"
|
||||
@change="handleTableChange"
|
||||
>
|
||||
<template #empty>
|
||||
<template #emptyText>
|
||||
<NoData text="暂无稿件" />
|
||||
</template>
|
||||
<template #columns>
|
||||
<a-table-column
|
||||
v-for="column in tableColumns"
|
||||
:key="column.dataIndex"
|
||||
:data-index="column.dataIndex"
|
||||
:fixed="column.fixed"
|
||||
:width="column.width"
|
||||
:min-width="column.minWidth"
|
||||
:sortable="column.sortable"
|
||||
:align="column.align"
|
||||
ellipsis
|
||||
tooltip
|
||||
>
|
||||
<template #title>
|
||||
<div class="flex items-center">
|
||||
<span class="cts mr-4px">{{ column.title }}</span>
|
||||
<a-tooltip v-if="column.tooltip" :content="column.tooltip" position="top">
|
||||
<icon-question-circle class="tooltip-icon color-#737478" size="16" />
|
||||
</a-tooltip>
|
||||
</div>
|
||||
</template>
|
||||
<Column
|
||||
v-for="column in tableColumns"
|
||||
:key="column.dataIndex"
|
||||
:dataIndex="column.dataIndex"
|
||||
:fixed="column.fixed"
|
||||
:width="column.width"
|
||||
:minWidth="column.minWidth"
|
||||
:sorter="column.sortable"
|
||||
:align="column.align"
|
||||
:ellipsis="true"
|
||||
>
|
||||
<template #title>
|
||||
<span class="cts mr-4px">{{ column.title }}</span>
|
||||
<Tooltip v-if="column.tooltip" :title="column.tooltip" placement="top">
|
||||
<icon-question-circle class="tooltip-icon color-#737478" size="16" />
|
||||
</Tooltip>
|
||||
</template>
|
||||
|
||||
<template v-if="column.dataIndex === 'customer_opinion'" #cell="{ record }">
|
||||
<p
|
||||
class="h-28px px-8px flex items-center rounded-2px w-fit"
|
||||
:style="{ background: getCustomerOpinionInfo(record.customer_opinion)?.bg }"
|
||||
>
|
||||
<span class="cts" :class="getCustomerOpinionInfo(record.customer_opinion)?.color">{{
|
||||
getCustomerOpinionInfo(record.customer_opinion)?.label ?? '-'
|
||||
}}</span>
|
||||
</p>
|
||||
</template>
|
||||
<template v-else-if="column.dataIndex === 'platform'" #cell="{ record }">
|
||||
<template v-if="!PLATFORMS.find((item) => item.value === record.platform)"> - </template>
|
||||
<img
|
||||
v-else
|
||||
width="24"
|
||||
height="24"
|
||||
class="rounded-4px"
|
||||
:src="PLATFORMS.find((item) => item.value === record.platform)?.icon"
|
||||
/>
|
||||
</template>
|
||||
<template v-else-if="column.dataIndex === 'compliance_level'" #cell="{ record }">
|
||||
<span class="cts num !color-#6D4CFE">{{
|
||||
record.ai_review?.compliance_level ? `${record.ai_review?.compliance_level}%` : '-'
|
||||
}}</span>
|
||||
</template>
|
||||
<template v-else-if="column.dataIndex === 'title'" #cell="{ record }">
|
||||
<TextOverTips :context="record.title" :line="3" class="title" @click="onDetail(record)" />
|
||||
</template>
|
||||
<template v-else-if="column.dataIndex === 'type'" #cell="{ record }">
|
||||
<div class="flex items-center">
|
||||
<img
|
||||
:src="record.type === EnumManuscriptType.Image ? icon2 : icon3"
|
||||
width="16"
|
||||
height="16"
|
||||
class="mr-4px"
|
||||
/>
|
||||
<span class="cts" :class="record.type === EnumManuscriptType.Image ? '!color-#25C883' : '!color-#6D4CFE'">{{
|
||||
record.type === EnumManuscriptType.Image ? '图文' : '视频'
|
||||
}}</span>
|
||||
</div>
|
||||
</template>
|
||||
<template v-else-if="['uploader', 'last_modifier'].includes(column.dataIndex)" #cell="{ record }">
|
||||
{{ record[column.dataIndex].name || record[column.dataIndex].mobile }}
|
||||
</template>
|
||||
<template
|
||||
#cell="{ record }"
|
||||
v-else-if="
|
||||
['created_at', 'last_modified_at', 'audit_started_at', 'audit_passed_at'].includes(column.dataIndex)
|
||||
"
|
||||
<template v-if="column.dataIndex === 'customer_opinion'" #customRender="{ record }">
|
||||
<p
|
||||
class="h-28px px-8px flex items-center rounded-2px w-fit"
|
||||
:style="{ background: getCustomerOpinionInfo(record.customer_opinion)?.bg }"
|
||||
>
|
||||
<span class="cts num">{{ exactFormatTime(record[column.dataIndex]) }}</span>
|
||||
</template>
|
||||
<template v-else-if="column.dataIndex === 'cover'" #cell="{ record }">
|
||||
<HoverImagePreview :src="record.cover">
|
||||
<a-image :width="64" :height="64" :src="record.cover" class="!rounded-6px" fit="cover">
|
||||
<template #error>
|
||||
<img :src="icon4" class="w-full h-full" />
|
||||
</template>
|
||||
</a-image>
|
||||
</HoverImagePreview>
|
||||
</template>
|
||||
<template v-else-if="column.dataIndex === 'operation'" #cell="{ record }">
|
||||
<div class="flex items-center">
|
||||
<img class="mr-8px cursor-pointer" :src="icon1" width="14" height="14" @click="onDelete(record)" />
|
||||
<a-button type="outline" size="mini" @click="onShare(record)" v-if="audit_status === AuditStatus.Passed"
|
||||
>分享</a-button
|
||||
>
|
||||
<a-button
|
||||
type="outline"
|
||||
size="mini"
|
||||
@click="onCheck(record)"
|
||||
v-else-if="audit_status === AuditStatus.Pending"
|
||||
>审核</a-button
|
||||
>
|
||||
<a-button type="outline" size="mini" @click="onScan(record)" v-else>查看</a-button>
|
||||
</div>
|
||||
</template>
|
||||
<template v-else #cell="{ record }">
|
||||
{{ formatTableField(column, record, true) }}
|
||||
</template>
|
||||
</a-table-column>
|
||||
</template>
|
||||
</a-table>
|
||||
<span class="cts" :class="getCustomerOpinionInfo(record.customer_opinion)?.color">{{
|
||||
getCustomerOpinionInfo(record.customer_opinion)?.label ?? '-'
|
||||
}}</span>
|
||||
</p>
|
||||
</template>
|
||||
<template v-else-if="column.dataIndex === 'platform'" #customRender="{ record }">
|
||||
<template v-if="!PLATFORMS.find((item) => item.value === record.platform)"> - </template>
|
||||
<img
|
||||
v-else
|
||||
width="24"
|
||||
height="24"
|
||||
class="rounded-4px"
|
||||
:src="PLATFORMS.find((item) => item.value === record.platform)?.icon"
|
||||
/>
|
||||
</template>
|
||||
<template v-else-if="column.dataIndex === 'compliance_level'" #customRender="{ record }">
|
||||
<span class="cts num !color-#6D4CFE">{{
|
||||
record.ai_review?.compliance_level ? `${record.ai_review?.compliance_level}%` : '-'
|
||||
}}</span>
|
||||
</template>
|
||||
<template v-else-if="column.dataIndex === 'title'" #customRender="{ record }">
|
||||
<TextOverTips :context="record.title" :line="3" class="title" @click="onDetail(record)" />
|
||||
</template>
|
||||
<template v-else-if="column.dataIndex === 'type'" #customRender="{ record }">
|
||||
<div class="flex items-center">
|
||||
<img :src="record.type === EnumManuscriptType.Image ? icon2 : icon3" width="16" height="16" class="mr-4px" />
|
||||
<span class="cts" :class="record.type === EnumManuscriptType.Image ? '!color-#25C883' : '!color-#6D4CFE'">{{
|
||||
record.type === EnumManuscriptType.Image ? '图文' : '视频'
|
||||
}}</span>
|
||||
</div>
|
||||
</template>
|
||||
<template v-else-if="['uploader', 'last_modifier'].includes(column.dataIndex)" #customRender="{ record }">
|
||||
{{ record[column.dataIndex].name || record[column.dataIndex].mobile }}
|
||||
</template>
|
||||
<template
|
||||
#customRender="{ record }"
|
||||
v-else-if="['created_at', 'last_modified_at', 'audit_started_at', 'audit_passed_at'].includes(column.dataIndex)"
|
||||
>
|
||||
<span class="cts num">{{ exactFormatTime(record[column.dataIndex]) }}</span>
|
||||
</template>
|
||||
<template v-else-if="column.dataIndex === 'cover'" #customRender="{ record }">
|
||||
<HoverImagePreview :src="record.cover">
|
||||
<ImgLazyLoad :width="64" :height="64" :src="record.cover" class="!rounded-6px" />
|
||||
</HoverImagePreview>
|
||||
</template>
|
||||
<template v-else-if="column.dataIndex === 'operation'" #customRender="{ record }">
|
||||
<div class="flex items-center">
|
||||
<img class="mr-8px cursor-pointer" :src="icon1" width="14" height="14" @click="onDelete(record)" />
|
||||
<Button type="primary" ghost size="small" @click="onShare(record)" v-if="audit_status === AuditStatus.Passed"
|
||||
>分享</Button
|
||||
>
|
||||
<Button
|
||||
type="primary"
|
||||
ghost
|
||||
size="small"
|
||||
@click="onCheck(record)"
|
||||
v-else-if="audit_status === AuditStatus.Pending"
|
||||
>审核</Button
|
||||
>
|
||||
<Button type="primary" ghost size="small" @click="onScan(record)" v-else>查看</Button>
|
||||
</div>
|
||||
</template>
|
||||
<template v-else #customRender="{ record }">
|
||||
{{ formatTableField(column, record, true) }}
|
||||
</template>
|
||||
</Column>
|
||||
</Table>
|
||||
|
||||
<ShareModal ref="shareModalRef" />
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref } from 'vue';
|
||||
import { Button, Tooltip, Table, Image } from 'ant-design-vue';
|
||||
const { Column } = Table;
|
||||
import { formatTableField, exactFormatTime } from '@/utils/tools';
|
||||
import { EnumManuscriptType } from '@/views/material-center/components/finished-products/manuscript/list/constants';
|
||||
import { patchWorkAuditsAudit } from '@/api/all/generationWorkshop';
|
||||
@ -139,16 +123,17 @@ import { AuditStatus } from '@/views/material-center/components/finished-product
|
||||
|
||||
import { slsWithCatch } from '@/utils/stroage.ts';
|
||||
|
||||
import TextOverTips from '@/components/text-over-tips';
|
||||
import TextOverTips from '@/components/text-over-tips'
|
||||
import ImgLazyLoad from "@/components/img-lazy-load";
|
||||
import ShareModal from '@/views/material-center/components/finished-products/manuscript/components/share-manuscript-modal/share-modal.vue';
|
||||
import HoverImagePreview from '@/components/hover-image-preview';
|
||||
|
||||
import icon1 from '@/assets/img/media-account/icon-delete.png';
|
||||
import icon2 from '@/assets/img/creative-generation-workshop/icon-photo.png';
|
||||
import icon3 from '@/assets/img/creative-generation-workshop/icon-video.png';
|
||||
import icon4 from '@/assets/img/error-img.png';
|
||||
// import icon4 from '@/assets/img/error-img.png';
|
||||
|
||||
const emits = defineEmits([ 'sorterChange', 'delete', 'select', 'selectAll']);
|
||||
const emits = defineEmits(['sorterChange', 'delete', 'select', 'selectAll']);
|
||||
const router = useRouter();
|
||||
|
||||
const props = defineProps({
|
||||
@ -160,10 +145,6 @@ const props = defineProps({
|
||||
type: Array,
|
||||
default: () => [],
|
||||
},
|
||||
rowSelection: {
|
||||
type: Array,
|
||||
default: () => [],
|
||||
},
|
||||
selectedRowKeys: {
|
||||
type: Array,
|
||||
default: () => [],
|
||||
@ -176,8 +157,20 @@ const props = defineProps({
|
||||
const tableRef = ref(null);
|
||||
const shareModalRef = ref(null);
|
||||
|
||||
const handleSorterChange = (column, order) => {
|
||||
emits('sorterChange', column, order === 'ascend' ? 'asc' : 'desc');
|
||||
const handleTableChange = (pagination, filters, sorter) => {
|
||||
if (sorter && sorter.field) {
|
||||
emits('sorterChange', sorter.field, sorter.order === 'ascend' ? 'asc' : 'desc');
|
||||
}
|
||||
};
|
||||
|
||||
const rowSelection = {
|
||||
selectedRowKeys: computed(() => props.selectedRowKeys),
|
||||
onSelect: (record, selected) => {
|
||||
emits('select', record, selected);
|
||||
},
|
||||
onSelectAll: (selected) => {
|
||||
emits('selectAll', selected);
|
||||
},
|
||||
};
|
||||
const onDelete = (item) => {
|
||||
emits('delete', item);
|
||||
|
||||
@ -219,7 +219,7 @@ export const INITIAL_QUERY = {
|
||||
title: '',
|
||||
created_at: [],
|
||||
audit_started_at: [],
|
||||
audit_platform: '',
|
||||
audit_platform: undefined,
|
||||
sort_column: undefined,
|
||||
sort_order: undefined,
|
||||
};
|
||||
|
||||
@ -13,28 +13,29 @@
|
||||
class="flex justify-end mb-12px"
|
||||
v-if="[AuditStatus.Pending, AuditStatus.Auditing].includes(query.audit_status)"
|
||||
>
|
||||
<a-button
|
||||
type="outline"
|
||||
<Button
|
||||
type="primary"
|
||||
ghost
|
||||
class="w-fit"
|
||||
size="medium"
|
||||
@click="handleBatchCheck"
|
||||
v-if="query.audit_status === AuditStatus.Pending"
|
||||
>批量审核</a-button
|
||||
>批量审核</Button
|
||||
>
|
||||
<a-button
|
||||
type="outline"
|
||||
<Button
|
||||
type="primary"
|
||||
ghost
|
||||
class="w-fit"
|
||||
size="medium"
|
||||
@click="handleBatchView"
|
||||
v-if="query.audit_status === AuditStatus.Auditing"
|
||||
>批量查看</a-button
|
||||
>批量查看</Button
|
||||
>
|
||||
</div>
|
||||
|
||||
<ManuscriptCheckTable
|
||||
:key="query.audit_status"
|
||||
:tableColumns="tableColumns"
|
||||
:rowSelection="rowSelection"
|
||||
:selectedRowKeys="selectedRowKeys"
|
||||
:dataSource="dataSource"
|
||||
:audit_status="query.audit_status"
|
||||
@ -44,16 +45,15 @@
|
||||
@selectAll="handleSelectAll"
|
||||
/>
|
||||
<div v-if="pageInfo.total > 0" class="pagination-row">
|
||||
<a-pagination
|
||||
<Pagination
|
||||
:total="pageInfo.total"
|
||||
size="mini"
|
||||
show-total
|
||||
show-jumper
|
||||
show-page-size
|
||||
size="small"
|
||||
:showTotal="(total, range) => `共 ${total} 条`"
|
||||
showSizeChanger
|
||||
showQuickJumper
|
||||
:current="pageInfo.page"
|
||||
:page-size="pageInfo.page_size"
|
||||
:pageSize="pageInfo.page_size"
|
||||
@change="onPageChange"
|
||||
@page-size-change="onPageSizeChange"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
@ -62,7 +62,7 @@
|
||||
</div>
|
||||
</template>
|
||||
<script lang="jsx" setup>
|
||||
import { Button, Message as AMessage } from '@arco-design/web-vue';
|
||||
import { Button, Pagination, message } from 'ant-design-vue';
|
||||
import FilterBlock from './components/filter-block';
|
||||
import ManuscriptCheckTable from './components/manuscript-check-table';
|
||||
import DeleteManuscriptModal from './components/manuscript-check-table/delete-manuscript-modal.vue';
|
||||
@ -83,22 +83,16 @@ const props = defineProps({
|
||||
const {
|
||||
dataSource,
|
||||
pageInfo,
|
||||
rowSelection,
|
||||
onPageChange,
|
||||
onPageSizeChange,
|
||||
resetPageInfo,
|
||||
selectedRowKeys,
|
||||
selectedRows,
|
||||
handleSelect,
|
||||
handleSelectAll,
|
||||
DEFAULT_PAGE_INFO,
|
||||
} = useTableSelectionWithPagination({
|
||||
onPageChange: () => {
|
||||
getData();
|
||||
},
|
||||
onPageSizeChange: () => {
|
||||
getData();
|
||||
},
|
||||
});
|
||||
const router = useRouter();
|
||||
const tableColumns = ref([]);
|
||||
@ -140,7 +134,7 @@ const handleSorterChange = (column, order) => {
|
||||
};
|
||||
const handleBatchCheck = () => {
|
||||
if (!selectedRows.value.length) {
|
||||
AMessage.warning('请选择需审核的内容稿件');
|
||||
message.warning('请选择需审核的内容稿件');
|
||||
return;
|
||||
}
|
||||
|
||||
@ -151,7 +145,7 @@ const handleBatchCheck = () => {
|
||||
};
|
||||
const handleBatchView = () => {
|
||||
if (!selectedRows.value.length) {
|
||||
AMessage.warning('请选择需查看的内容稿件');
|
||||
message.warning('请选择需查看的内容稿件');
|
||||
return;
|
||||
}
|
||||
|
||||
@ -175,7 +169,6 @@ const handleDelete = (item) => {
|
||||
deleteManuscriptModalRef.value?.open({ id, name: `“${title}”` });
|
||||
};
|
||||
|
||||
|
||||
watch(
|
||||
() => props.audit_status,
|
||||
(newVal) => {
|
||||
|
||||
@ -1,9 +1,10 @@
|
||||
<template>
|
||||
<a-modal
|
||||
v-model:visible="visible"
|
||||
<Modal
|
||||
v-model:open="visible"
|
||||
:title="action === 'exit' ? '退出审核' : '切换内容稿件'"
|
||||
width="480px"
|
||||
@close="onClose"
|
||||
centered
|
||||
@cancel="onClose"
|
||||
>
|
||||
<div class="flex items-center">
|
||||
<img :src="icon1" width="20" height="20" class="mr-12px" />
|
||||
@ -14,16 +15,17 @@
|
||||
}}</span>
|
||||
</div>
|
||||
<template #footer>
|
||||
<a-button size="medium" @click="onClose">继续编辑</a-button>
|
||||
<a-button type="primary" class="ml-8px" size="medium" @click="onConfirm">
|
||||
<Button size="medium" @click="onClose">继续编辑</Button>
|
||||
<Button type="primary" class="ml-8px" size="medium" @click="onConfirm">
|
||||
{{ action === 'exit' ? '确认退出' : '确认切换' }}
|
||||
</a-button>
|
||||
</Button>
|
||||
</template>
|
||||
</a-modal>
|
||||
</Modal>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref } from 'vue';
|
||||
import { Button, Modal } from 'ant-design-vue';
|
||||
import icon1 from '@/assets/img/media-account/icon-warn-1.png';
|
||||
import { useRouter } from 'vue-router';
|
||||
|
||||
|
||||
@ -1,10 +1,11 @@
|
||||
<template>
|
||||
<a-modal
|
||||
v-model:visible="visible"
|
||||
<Modal
|
||||
v-model:open="visible"
|
||||
title="提示"
|
||||
width="480px"
|
||||
@close="onClose"
|
||||
modal-class="upload-success11-modal"
|
||||
centered
|
||||
wrapClassName="upload-success11-modal"
|
||||
:footer="null"
|
||||
>
|
||||
<div class="flex items-center flex-col justify-center">
|
||||
@ -13,14 +14,12 @@
|
||||
<p class="text-14px lh-22px font-400 color-#737478 ld">想让内容更抓眼球、更吸流量吗?</p>
|
||||
<p class="text-14px lh-22px font-400 color-#737478 ld">试试「内容稿件分析」功能吧!</p>
|
||||
</div>
|
||||
<!-- <template #footer>
|
||||
<a-button type="primary" class="ml-8px" size="medium" @click="onConfirm">内容稿件分析</a-button>
|
||||
</template> -->
|
||||
</a-modal>
|
||||
</Modal>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref } from 'vue';
|
||||
import { Button, Modal } from 'ant-design-vue';
|
||||
import icon1 from '@/assets/img/media-account/icon-feedback-success.png';
|
||||
|
||||
const router = useRouter();
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
<script lang="jsx">
|
||||
import { Drawer, Image } from '@arco-design/web-vue';
|
||||
import { Drawer, Image } from 'ant-design-vue';
|
||||
import TextOverTips from '@/components/text-over-tips';
|
||||
|
||||
import icon1 from '@/assets/img/error-img.png';
|
||||
@ -32,12 +32,12 @@ export default {
|
||||
return () => (
|
||||
<Drawer
|
||||
title="审核列表"
|
||||
visible={visible.value}
|
||||
v-model:open={visible.value}
|
||||
width={420}
|
||||
class="check-list-drawer-xt"
|
||||
footer={false}
|
||||
header={false}
|
||||
onCancel={onClose}
|
||||
rootClassName="check-list-drawer-xt"
|
||||
footer={null}
|
||||
closable={false}
|
||||
onClose={onClose}
|
||||
>
|
||||
<div class="flex justify-between items-center h-56px px-24px">
|
||||
<div class="flex items-center">
|
||||
@ -61,13 +61,12 @@ export default {
|
||||
height={48}
|
||||
preview={false}
|
||||
src={item.cover}
|
||||
class="!rounded-4px mr-8px"
|
||||
fit="cover"
|
||||
class="!rounded-4px"
|
||||
v-slots={{
|
||||
error: () => <img src={icon1} class="w-full h-full" />,
|
||||
}}
|
||||
/>
|
||||
<div class="flex-1 overflow-hidden flex flex-col items-start">
|
||||
<div class="flex-1 overflow-hidden flex flex-col items-start ml-8px">
|
||||
<TextOverTips context={item.title} class={`cts !color-#211F24 title mb-4px !text-14px`} />
|
||||
<p class="cts !text-14px">{`合规程度:${
|
||||
item.ai_review?.compliance_level ? `${item.ai_review?.compliance_level}%` : '-'
|
||||
|
||||
@ -1,43 +1,44 @@
|
||||
.check-list-drawer-xt {
|
||||
.arco-drawer-mask {
|
||||
box-shadow: 0 8px 16px 0 rgba(0, 0, 0, 0.15);
|
||||
.ant-drawer-mask {
|
||||
background-color: transparent;
|
||||
}
|
||||
.arco-drawer {
|
||||
box-shadow: 0 8px 16px 0 rgba(0, 0, 0, 0.15);
|
||||
.arco-drawer-body {
|
||||
overflow: hidden;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
padding: 0 0 24px;
|
||||
.cts {
|
||||
color: var(--Text-1, #939499);
|
||||
.ant-drawer-header {
|
||||
display: none;
|
||||
}
|
||||
.ant-drawer-body {
|
||||
overflow: hidden;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
padding: 0 0 24px;
|
||||
.cts {
|
||||
color: var(--Text-1, #939499);
|
||||
|
||||
font-family: $font-family-regular;
|
||||
font-size: 16px;
|
||||
font-style: normal;
|
||||
font-weight: 400;
|
||||
line-height: 24px;
|
||||
&.bold {
|
||||
color: var(--Text-1, #211f24);
|
||||
font-family: $font-family-medium;
|
||||
}
|
||||
font-family: $font-family-regular;
|
||||
font-size: 16px;
|
||||
font-style: normal;
|
||||
font-weight: 400;
|
||||
line-height: 24px;
|
||||
&.bold {
|
||||
color: var(--Text-1, #211f24);
|
||||
font-family: $font-family-medium;
|
||||
}
|
||||
.card-item {
|
||||
cursor: pointer;
|
||||
border: 1px solid transparent;
|
||||
transition: all;
|
||||
&:hover {
|
||||
background-color: #e6e6e8;
|
||||
}
|
||||
&:not(:last-child) {
|
||||
margin-bottom: 12px;
|
||||
}
|
||||
&.active {
|
||||
border-color: #6d4cfe;
|
||||
background-color: #f0edff;
|
||||
:deep(.overflow-text) {
|
||||
font-family: $font-family-medium !important;
|
||||
}
|
||||
}
|
||||
.card-item {
|
||||
cursor: pointer;
|
||||
border: 1px solid transparent;
|
||||
transition: all;
|
||||
&:hover {
|
||||
background-color: #e6e6e8;
|
||||
}
|
||||
&:not(:last-child) {
|
||||
margin-bottom: 12px;
|
||||
}
|
||||
&.active {
|
||||
border-color: #6d4cfe;
|
||||
background-color: #f0edff;
|
||||
:deep(.overflow-text) {
|
||||
font-family: $font-family-medium !important;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -14,10 +14,10 @@ export const TAB_LIST = [
|
||||
label: '文本',
|
||||
value: enumTab.TEXT,
|
||||
},
|
||||
// {
|
||||
// label: '图片',
|
||||
// value: enumTab.IMAGE,
|
||||
// },
|
||||
{
|
||||
label: '图片',
|
||||
value: enumTab.IMAGE,
|
||||
},
|
||||
];
|
||||
|
||||
export enum Enum_Level {
|
||||
|
||||
@ -24,6 +24,8 @@
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { Input } from 'ant-design-vue';
|
||||
const {TextArea} = Input
|
||||
import { ref, computed, watch, defineProps, defineEmits, onMounted, onUnmounted } from 'vue';
|
||||
import { escapeRegExp } from './constants';
|
||||
|
||||
|
||||
@ -1,23 +1,13 @@
|
||||
<script lang="jsx">
|
||||
import axios from 'axios';
|
||||
import { Swiper, SwiperSlide } from 'swiper/vue';
|
||||
import { Button, Form, Input, FormItem, Tabs, message, Image, Upload, Spin } from 'ant-design-vue';
|
||||
import { IconLoading } from '@arco-design/web-vue/es/icon';
|
||||
import {
|
||||
Image,
|
||||
Form,
|
||||
FormItem,
|
||||
Input,
|
||||
Textarea,
|
||||
Button,
|
||||
Tabs,
|
||||
Upload,
|
||||
TabPane,
|
||||
Spin,
|
||||
Message as AMessage,
|
||||
} from '@arco-design/web-vue';
|
||||
import TextOverTips from '@/components/text-over-tips';
|
||||
import HighlightTextarea from './highlight-textarea';
|
||||
|
||||
const { TabPane } = Tabs;
|
||||
|
||||
import 'swiper/css';
|
||||
import 'swiper/css/navigation';
|
||||
import { Navigation } from 'swiper/modules';
|
||||
@ -87,7 +77,7 @@ export default {
|
||||
|
||||
const onAgainCheck = () => {
|
||||
if (!isTextTab.value && !props.modelValue.files?.length) {
|
||||
AMessage.warning('请先上传需审核图片');
|
||||
message.warning('请先上传需审核图片');
|
||||
return;
|
||||
}
|
||||
emit('againCheck');
|
||||
@ -99,15 +89,7 @@ export default {
|
||||
activeTab.value = key;
|
||||
};
|
||||
const validate = () => {
|
||||
return new Promise((resolve, reject) => {
|
||||
formRef.value?.validate((errors) => {
|
||||
if (errors) {
|
||||
reject();
|
||||
} else {
|
||||
resolve();
|
||||
}
|
||||
});
|
||||
});
|
||||
return formRef.value?.validate();
|
||||
};
|
||||
const reset = () => {
|
||||
formRef.value?.resetFields?.();
|
||||
@ -139,24 +121,19 @@ export default {
|
||||
<Upload
|
||||
ref={uploadRef}
|
||||
action="/"
|
||||
draggable
|
||||
class="w-fit"
|
||||
custom-request={(option) => uploadImage(option, action)}
|
||||
customRequest={(option) => uploadImage(option, action)}
|
||||
accept=".jpg,.jpeg,.png,.gif,.webp"
|
||||
show-file-list={false}
|
||||
showUploadList={false}
|
||||
multiple
|
||||
>
|
||||
{{
|
||||
'upload-button': () => <UploadBtn />,
|
||||
}}
|
||||
<UploadBtn />
|
||||
</Upload>
|
||||
);
|
||||
};
|
||||
|
||||
const uploadImage = async (option, action = 'upload') => {
|
||||
const {
|
||||
fileItem: { file },
|
||||
} = option;
|
||||
const { file } = option;
|
||||
|
||||
const { name, size, type } = file;
|
||||
const response = await getImagePreSignedUrl({ suffix: getFileExtension(name) });
|
||||
@ -190,11 +167,11 @@ export default {
|
||||
const renderFooterRow = () => {
|
||||
return (
|
||||
<>
|
||||
<Button class="mr-12px" size="medium" onClick={onAgainCheck} disabled={isDisabled.value}>
|
||||
<Button class="mr-12px" onClick={onAgainCheck} disabled={isDisabled.value}>
|
||||
再次审核
|
||||
</Button>
|
||||
{isTextTab.value ? (
|
||||
<Button size="medium" type="outline" class="w-123px check-btn" onClick={onAiReplace} disabled={isDisabled.value}>
|
||||
<Button type="primary" ghost class="w-123px check-btn" onClick={onAiReplace} disabled={isDisabled.value}>
|
||||
{aiReplaceLoading.value ? (
|
||||
<>
|
||||
<IconLoading size={14} />
|
||||
@ -210,7 +187,7 @@ export default {
|
||||
) : (
|
||||
<div class="w-88px">
|
||||
{renderUpload(
|
||||
<Button size="medium" type="outline">
|
||||
<Button type="primary" ghost>
|
||||
图片替换
|
||||
</Button>,
|
||||
'replaceImage',
|
||||
@ -223,17 +200,17 @@ export default {
|
||||
const renderTextForm = () => {
|
||||
return (
|
||||
<Form ref={formRef} model={props.modelValue} rules={FORM_RULES} layout="vertical" auto-label-width>
|
||||
<FormItem label="标题" field="title" required>
|
||||
<FormItem label="标题" name="title" required>
|
||||
<Input
|
||||
v-model={props.modelValue.title}
|
||||
v-model:value={props.modelValue.title}
|
||||
placeholder="请输入标题"
|
||||
size="large"
|
||||
maxLength={30}
|
||||
show-word-limit
|
||||
maxlength={30}
|
||||
showCount
|
||||
disabled={isDisabled.value}
|
||||
/>
|
||||
</FormItem>
|
||||
<FormItem label="作品描述" field="content" class="flex-1 content-form-item">
|
||||
<FormItem label="作品描述" name="content" class="flex-1 content-form-item">
|
||||
<HighlightTextarea
|
||||
v-model={props.modelValue.content}
|
||||
disabled={isDisabled.value}
|
||||
@ -409,9 +386,9 @@ export default {
|
||||
<div class="right-box">
|
||||
<p class="cts bold !text-16px !lh-24px !color-#211F24 mb-16px">审核结果</p>
|
||||
<Spin
|
||||
loading={true}
|
||||
spinning={true}
|
||||
tip={`${isTextTab.value ? '文本' : '图片'}检测中`}
|
||||
size={72}
|
||||
size="large"
|
||||
class="h-298px !flex flex-col justify-center items-center"
|
||||
/>
|
||||
</div>
|
||||
@ -421,7 +398,7 @@ export default {
|
||||
<div class="right-box">
|
||||
<p class="cts bold !text-16px !lh-24px !color-#211F24 mb-16px">审核结果</p>
|
||||
{props.getDataLoading ? (
|
||||
<Spin loading={true} size={72} class="h-298px !flex justify-center items-center" />
|
||||
<Spin spinning={true} size="large" class="h-298px !flex justify-center items-center" />
|
||||
) : (
|
||||
renderCheckSuccessBox()
|
||||
)}
|
||||
@ -440,22 +417,20 @@ export default {
|
||||
<div class="h-full w-full px-24px pt-16px pb-24px content-wrap flex">
|
||||
<div class="flex-2 left-box mr-24px flex flex-col">
|
||||
<div class="flex-1 mb-12px rounded-8px border-1px pt-8px flex flex-col pb-16px bg-#F7F8FA border-#E6E6E8 border-solid">
|
||||
<Tabs v-model={activeTab.value} onTabClick={handleTabClick} class="mb-16px">
|
||||
<Tabs activeKey={activeTab.value} onChange={handleTabClick} class="mb-16px">
|
||||
{TAB_LIST.map((item) => (
|
||||
<TabPane
|
||||
key={item.value}
|
||||
v-slots={{
|
||||
title: () => (
|
||||
<div class="flex items-center relative">
|
||||
<span>{item.label}</span>
|
||||
{
|
||||
// activeTab.value === item.value && aiReview.value?.violation_items.length > 0 && (
|
||||
// <icon-exclamation-circle-fill size={14} class="color-#F64B31 absolute right--10px top-0" />
|
||||
// )
|
||||
}
|
||||
</div>
|
||||
),
|
||||
}}
|
||||
tab={
|
||||
<div class="flex items-center relative">
|
||||
<span>{item.label}</span>
|
||||
{
|
||||
// activeTab.value === item.value && aiReview.value?.violation_items.length > 0 && (
|
||||
// <icon-exclamation-circle-fill size={14} class="color-#F64B31 absolute right--10px top-0" />
|
||||
// )
|
||||
}
|
||||
</div>
|
||||
}
|
||||
/>
|
||||
))}
|
||||
</Tabs>
|
||||
|
||||
@ -23,43 +23,32 @@
|
||||
}
|
||||
|
||||
.left-box {
|
||||
:deep(.arco-tabs) {
|
||||
.arco-tabs-nav {
|
||||
.arco-tabs-tab {
|
||||
height: 40px;
|
||||
// padding: 0 8px;
|
||||
margin: 0 16px;
|
||||
}
|
||||
&::before {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
.arco-tabs-content {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
:deep(.arco-form) {
|
||||
:deep(.ant-form) {
|
||||
height: 100%;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
.arco-form-item {
|
||||
.ant-form-item {
|
||||
margin-bottom: 24px;
|
||||
.arco-form-item-label-col {
|
||||
.arco-form-item-label {
|
||||
.ant-form-item-label-col {
|
||||
.ant-form-item-label {
|
||||
color: #939499;
|
||||
}
|
||||
}
|
||||
}
|
||||
.content-form-item {
|
||||
margin-bottom: 0;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
.arco-form-item-wrapper-col {
|
||||
flex: 1;
|
||||
.arco-form-item-content-wrapper,
|
||||
.arco-form-item-content,
|
||||
.arco-textarea-wrapper {
|
||||
height: 100%;
|
||||
|
||||
.ant-row {
|
||||
height: 100%;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
.ant-form-item-control-input {
|
||||
flex: 1;
|
||||
.ant-form-item-control-input-content,
|
||||
.ant-form-item-control-input-content,
|
||||
.ant-textarea-wrapper {
|
||||
height: 100%;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
<script lang="jsx">
|
||||
import { Image } from '@arco-design/web-vue';
|
||||
import { Image } from 'ant-design-vue';
|
||||
import { Swiper, SwiperSlide } from 'swiper/vue';
|
||||
import TextOverTips from '@/components/text-over-tips';
|
||||
|
||||
@ -56,13 +56,13 @@ export default {
|
||||
height={48}
|
||||
preview={false}
|
||||
src={item.cover}
|
||||
class="!rounded-4px mr-8px"
|
||||
class="!rounded-4px"
|
||||
fit="cover"
|
||||
v-slots={{
|
||||
error: () => <img src={icon1} class="w-full h-full" />,
|
||||
}}
|
||||
/>
|
||||
<div class="flex-1 overflow-hidden flex flex-col items-start">
|
||||
<div class="flex-1 overflow-hidden flex flex-col items-start ml-8px">
|
||||
<TextOverTips context={item.title} class={`cts !color-#211F24 title mb-4px`} />
|
||||
<p class="cts">{`合规程度:${item.ai_review?.compliance_level ? `${item.ai_review?.compliance_level}%` : '-'}`}</p>
|
||||
</div>
|
||||
|
||||
@ -1,5 +1,6 @@
|
||||
<script lang="jsx">
|
||||
import { Button, Message as AMessage, Spin } from '@arco-design/web-vue';
|
||||
import { Button, message } from 'ant-design-vue';
|
||||
import { Spin } from 'ant-design-vue';
|
||||
import CancelCheckModal from './cancel-check-modal.vue';
|
||||
import CheckSuccessModal from './check-success-modal.vue';
|
||||
import HeaderCard from './components/header-card';
|
||||
@ -135,14 +136,14 @@ export default {
|
||||
};
|
||||
const onSave = async () => {
|
||||
if (!selectCardInfo.value.title) {
|
||||
AMessage.warning('标题不能为空');
|
||||
message.warning('标题不能为空');
|
||||
}
|
||||
|
||||
contentCardRef.value?.validate().then(async () => {
|
||||
const { code, data } = await putWorkAuditsUpdate(selectCardInfo.value);
|
||||
if (code === 200) {
|
||||
isSaved.value = true;
|
||||
AMessage.success('当前内容稿件已保存');
|
||||
message.success('当前内容稿件已保存');
|
||||
}
|
||||
});
|
||||
};
|
||||
@ -181,13 +182,13 @@ export default {
|
||||
const renderFooterRow = () => {
|
||||
return (
|
||||
<>
|
||||
<Button size="medium" type="outline" class="mr-12px" onClick={onExit}>
|
||||
<Button type="primary" ghost class="mr-12px" onClick={onExit}>
|
||||
退出
|
||||
</Button>
|
||||
<Button size="medium" type="outline" class="mr-12px" onClick={onSave}>
|
||||
<Button type="primary" ghost class="mr-12px" onClick={onSave}>
|
||||
保存
|
||||
</Button>
|
||||
<Button type="primary" size="medium" onClick={onSubmit} loading={submitLoading.value}>
|
||||
<Button type="primary" onClick={onSubmit} loading={submitLoading.value}>
|
||||
{submitLoading.value ? '通过审核中...' : '通过审核'}
|
||||
</Button>
|
||||
</>
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
<template>
|
||||
<a-form-item field="files">
|
||||
<FormItem name="files">
|
||||
<template #label>
|
||||
<div class="flex items-center">
|
||||
<span class="cts !color-#211F24 mr-4px">图片</span>
|
||||
@ -23,32 +23,31 @@
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<a-upload
|
||||
<Upload
|
||||
v-if="files.length < 18"
|
||||
ref="uploadRef"
|
||||
action="/"
|
||||
draggable
|
||||
:custom-request="(option) => emit('upload', option)"
|
||||
:customRequest="(option) => emit('upload', option)"
|
||||
accept=".jpg,.jpeg,.png,.gif,.webp"
|
||||
:show-file-list="false"
|
||||
:showUploadList="false"
|
||||
multiple
|
||||
class="!flex !items-center"
|
||||
:limit="18 - files.length"
|
||||
>
|
||||
<template #upload-button>
|
||||
<template #default>
|
||||
<div class="upload-box">
|
||||
<icon-plus size="14" class="mb-16px color-#3C4043" />
|
||||
<span class="cts !color-#211F24">上传图片</span>
|
||||
</div>
|
||||
</template>
|
||||
</a-upload>
|
||||
</Upload>
|
||||
</VueDraggable>
|
||||
</div>
|
||||
</a-form-item>
|
||||
</FormItem>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { VueDraggable } from 'vue-draggable-plus';
|
||||
import { FormItem, Upload } from 'ant-design-vue';
|
||||
|
||||
const props = defineProps({
|
||||
files: {
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
<script lang="jsx">
|
||||
import axios from 'axios';
|
||||
import { Form, FormItem, Input, Textarea, Upload, Message as AMessage, Button } from '@arco-design/web-vue';
|
||||
import { Button, Form, FormItem, Input, message, Upload } from 'ant-design-vue';
|
||||
// import CommonSelect from '@/components/common-select';
|
||||
// import { VueDraggable } from 'vue-draggable-plus';
|
||||
import TextOverTips from '@/components/text-over-tips';
|
||||
@ -11,6 +11,8 @@ import { formatFileSize, getVideoInfo, formatDuration, formatUploadSpeed } from
|
||||
import { EnumManuscriptType } from '@/views/material-center/components/finished-products/manuscript/list/constants.ts';
|
||||
import { getImagePreSignedUrl, getVideoPreSignedUrl } from '@/api/all/common';
|
||||
|
||||
const { TextArea } = Input;
|
||||
|
||||
// import icon1 from '@/assets/img/creative-generation-workshop/icon-close.png';
|
||||
|
||||
// 表单验证规则
|
||||
@ -128,9 +130,7 @@ export default {
|
||||
formData.value.videoInfo.uploadStatus = ENUM_UPLOAD_STATUS.UPLOADING;
|
||||
emit('updateVideoInfo', formData.value.videoInfo);
|
||||
|
||||
const {
|
||||
fileItem: { file },
|
||||
} = option;
|
||||
const { file } = option;
|
||||
setVideoInfo(file);
|
||||
|
||||
const response = await getVideoPreSignedUrl({ suffix: getFileExtension(file.name) });
|
||||
@ -161,13 +161,11 @@ export default {
|
||||
};
|
||||
// 文件上传处理
|
||||
const uploadImage = async (option) => {
|
||||
const {
|
||||
fileItem: { file },
|
||||
} = option;
|
||||
const { file } = option;
|
||||
|
||||
// 验证文件数量
|
||||
if (formData.value.files?.length >= 18) {
|
||||
AMessage.error('最多只能上传18张图片!');
|
||||
message.error('最多只能上传18张图片!');
|
||||
return;
|
||||
}
|
||||
const { name, size, type } = file;
|
||||
@ -189,15 +187,7 @@ export default {
|
||||
};
|
||||
|
||||
const validate = () => {
|
||||
return new Promise((resolve, reject) => {
|
||||
formRef.value?.validate((errors) => {
|
||||
if (errors) {
|
||||
reject(formData.value);
|
||||
} else {
|
||||
resolve();
|
||||
}
|
||||
});
|
||||
});
|
||||
return formRef.value?.validate();
|
||||
};
|
||||
|
||||
const resetForm = () => {
|
||||
@ -211,25 +201,18 @@ export default {
|
||||
<Upload
|
||||
ref={uploadRef}
|
||||
action="/"
|
||||
draggable
|
||||
custom-request={uploadVideo}
|
||||
customRequest={uploadVideo}
|
||||
accept=".mp4,.mov,.avi,.flv,.wmv"
|
||||
show-file-list={false}
|
||||
showUploadList={false}
|
||||
>
|
||||
{{
|
||||
'upload-button': () => {
|
||||
if (formData.value.videoInfo.uploadStatus === ENUM_UPLOAD_STATUS.DEFAULT) {
|
||||
return (
|
||||
<div class="upload-box">
|
||||
<icon-plus size="14" class="mb-16px color-#3C4043" />
|
||||
<span class="cts !color-#211F24">上传视频</span>
|
||||
</div>
|
||||
);
|
||||
} else {
|
||||
return <Button type="text">替换视频</Button>;
|
||||
}
|
||||
},
|
||||
}}
|
||||
{formData.value.videoInfo.uploadStatus === ENUM_UPLOAD_STATUS.DEFAULT ? (
|
||||
<div class="upload-box">
|
||||
<icon-plus size="14" class="mb-16px color-#3C4043" />
|
||||
<span class="cts !color-#211F24">上传视频</span>
|
||||
</div>
|
||||
) : (
|
||||
<Button type="text">替换视频</Button>
|
||||
)}
|
||||
</Upload>
|
||||
);
|
||||
};
|
||||
@ -238,7 +221,7 @@ export default {
|
||||
const isEnd = formData.value.videoInfo.uploadStatus === ENUM_UPLOAD_STATUS.END;
|
||||
return (
|
||||
<FormItem
|
||||
field="files"
|
||||
name="files"
|
||||
v-slots={{
|
||||
label: () => (
|
||||
<div class="flex items-center">
|
||||
@ -315,30 +298,31 @@ export default {
|
||||
|
||||
return () => (
|
||||
<Form ref={formRef} model={formData.value} rules={props.rules} layout="vertical" auto-label-width>
|
||||
<FormItem label="标题" field="title" required>
|
||||
<FormItem label="标题" name="title" required>
|
||||
<Input
|
||||
v-model={formData.value.title}
|
||||
v-model:value={formData.value.title}
|
||||
onInput={() => {
|
||||
console.log('onInput');
|
||||
onChange();
|
||||
emit('reValidate');
|
||||
}}
|
||||
placeholder="请输入标题"
|
||||
size="large"
|
||||
class="!w-500px"
|
||||
maxLength={30}
|
||||
show-word-limit
|
||||
maxlength={30}
|
||||
showCount
|
||||
/>
|
||||
</FormItem>
|
||||
|
||||
<FormItem label="作品描述" field="content">
|
||||
<Textarea
|
||||
v-model={formData.value.content}
|
||||
<FormItem label="作品描述" name="content">
|
||||
<TextArea
|
||||
v-model:value={formData.value.content}
|
||||
onInput={onChange}
|
||||
placeholder="请输入作品描述"
|
||||
size="large"
|
||||
class="textarea-box !w-784px"
|
||||
show-word-limit
|
||||
max-length={1000}
|
||||
showCount
|
||||
maxlength={1000}
|
||||
/>
|
||||
</FormItem>
|
||||
{isVideo.value ? (
|
||||
@ -352,7 +336,7 @@ export default {
|
||||
/>
|
||||
)}
|
||||
|
||||
{/* <FormItem label="所属项目" field="project_ids">
|
||||
{/* <FormItem label="所属项目" name="project_ids">
|
||||
<CommonSelect
|
||||
v-model={formData.value.project_ids}
|
||||
onChange={() => emit('change')}
|
||||
|
||||
@ -31,8 +31,6 @@
|
||||
}
|
||||
}
|
||||
.textarea-box {
|
||||
:deep(.arco-textarea) {
|
||||
height: 140px;
|
||||
max-height: 298px;
|
||||
}
|
||||
height: 140px;
|
||||
max-height: 298px;
|
||||
}
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
export const INITIAL_FORM = {
|
||||
audit_status: '',
|
||||
audit_status: undefined,
|
||||
sort_column: undefined,
|
||||
sort_order: undefined,
|
||||
};
|
||||
|
||||
@ -1,22 +1,15 @@
|
||||
<script lang="jsx">
|
||||
import {
|
||||
Input,
|
||||
Table,
|
||||
Modal,
|
||||
TableColumn,
|
||||
Checkbox,
|
||||
Pagination,
|
||||
Button,
|
||||
Tooltip,
|
||||
Notification,
|
||||
} from '@arco-design/web-vue';
|
||||
import { Button, Modal, Tooltip, Table, Pagination } from 'ant-design-vue';
|
||||
import CommonSelect from '@/components/common-select';
|
||||
import TextOverTips from '@/components/text-over-tips';
|
||||
import ShareModal from '@/views/material-center/components/finished-products/manuscript/components/share-manuscript-modal/share-modal';
|
||||
|
||||
import { INITIAL_FORM, TABLE_COLUMNS } from './constants';
|
||||
import { formatTableField, exactFormatTime } from '@/utils/tools';
|
||||
import { CHECK_STATUS, EnumManuscriptType } from '@/views/material-center/components/finished-products/manuscript/list/constants';
|
||||
import {
|
||||
CHECK_STATUS,
|
||||
EnumManuscriptType,
|
||||
} from '@/views/material-center/components/finished-products/manuscript/list/constants';
|
||||
import { useTableSelectionWithPagination } from '@/hooks/useTableSelectionWithPagination';
|
||||
import { getWorksPage, getWriterLinksGenerate } from '@/api/all/generationWorkshop.ts';
|
||||
|
||||
@ -31,8 +24,6 @@ export default {
|
||||
dataSource,
|
||||
pageInfo,
|
||||
onPageChange,
|
||||
onPageSizeChange,
|
||||
rowSelection,
|
||||
handleSelect,
|
||||
handleSelectAll,
|
||||
DEFAULT_PAGE_INFO,
|
||||
@ -40,9 +31,6 @@ export default {
|
||||
onPageChange: () => {
|
||||
getData();
|
||||
},
|
||||
onPageSizeChange: () => {
|
||||
getData();
|
||||
},
|
||||
});
|
||||
const visible = ref(false);
|
||||
const query = ref(cloneDeep(INITIAL_FORM));
|
||||
@ -86,42 +74,44 @@ export default {
|
||||
reset();
|
||||
};
|
||||
|
||||
const renderColumn = () => {
|
||||
return TABLE_COLUMNS.map((column) => (
|
||||
<TableColumn
|
||||
key={column.dataIndex}
|
||||
data-index={column.dataIndex}
|
||||
fixed={column.fixed}
|
||||
width={column.width}
|
||||
min-width={column.minWidth}
|
||||
sortable={column.sortable}
|
||||
align={column.align}
|
||||
ellipsis
|
||||
tooltip
|
||||
v-slots={{
|
||||
title: () => (
|
||||
<div class="flex items-center">
|
||||
<span class="cts mr-4px">{column.title}</span>
|
||||
{column.tooltip && (
|
||||
<Tooltip content={column.tooltip} position="top">
|
||||
<IconQuestionCircle class="tooltip-icon color-#737478" size={16} />
|
||||
</Tooltip>
|
||||
)}
|
||||
</div>
|
||||
),
|
||||
cell: ({ record }) => renderCell(record),
|
||||
}}
|
||||
/>
|
||||
));
|
||||
};
|
||||
// const renderColumn = () => {
|
||||
// return TABLE_COLUMNS.map((column) => (
|
||||
// <TableColumn
|
||||
// key={column.dataIndex}
|
||||
// data-index={column.dataIndex}
|
||||
// fixed={column.fixed}
|
||||
// width={column.width}
|
||||
// min-width={column.minWidth}
|
||||
// sortable={column.sortable}
|
||||
// align={column.align}
|
||||
// ellipsis
|
||||
// tooltip
|
||||
// v-slots={{
|
||||
// title: () => (
|
||||
// <>
|
||||
// <span class="cts mr-4px">{column.title}</span>
|
||||
// {column.tooltip && (
|
||||
// <Tooltip title={column.tooltip} placement="top">
|
||||
// <IconQuestionCircle class="tooltip-icon color-#737478" size={16} />
|
||||
// </Tooltip>
|
||||
// )}
|
||||
// </>
|
||||
// ),
|
||||
// cell: ({ record }) => renderCell(record),
|
||||
// }}
|
||||
// />
|
||||
// ));
|
||||
// };
|
||||
|
||||
const onShare = () => {
|
||||
shareModalRef.value?.open(selectedRowKeys.value);
|
||||
};
|
||||
const handleSorterChange = (column, order) => {
|
||||
query.value.sort_column = column;
|
||||
query.value.sort_order = order === 'ascend' ? 'asc' : 'desc';
|
||||
reload();
|
||||
const handleSorterChange = (pagination, filters, sorter) => {
|
||||
if (sorter && !Array.isArray(sorter) && sorter.columnKey) {
|
||||
query.value.sort_column = sorter.columnKey;
|
||||
query.value.sort_order = sorter.order === 'ascend' ? 'asc' : 'desc';
|
||||
reload();
|
||||
}
|
||||
};
|
||||
const getStatusInfo = (audit_status) => {
|
||||
return CHECK_STATUS.find((v) => v.id === audit_status) ?? {};
|
||||
@ -132,12 +122,13 @@ export default {
|
||||
return () => (
|
||||
<>
|
||||
<Modal
|
||||
v-model:visible={visible.value}
|
||||
v-model:open={visible.value}
|
||||
title="分享内容稿件"
|
||||
width="920px"
|
||||
onClose={onClose}
|
||||
unmount-on-close
|
||||
modal-class="share-manuscript-modal"
|
||||
onCancel={onClose}
|
||||
centered
|
||||
destroyOnClose
|
||||
wrapClassName="share-manuscript-modal"
|
||||
v-slots={{
|
||||
footer: () => (
|
||||
<div class="flex justify-between w-full items-center">
|
||||
@ -145,16 +136,8 @@ export default {
|
||||
已选择 <span class="cts color-#211F24 bold">{selectedRows.value.length}</span> 个
|
||||
</p>
|
||||
<div class="flex items-center">
|
||||
<Button size="medium" onClick={onClose}>
|
||||
取消
|
||||
</Button>
|
||||
<Button
|
||||
type="primary"
|
||||
class="ml-16px"
|
||||
size="medium"
|
||||
onClick={onShare}
|
||||
disabled={!selectedRows.value.length}
|
||||
>
|
||||
<Button onClick={onClose}>取消</Button>
|
||||
<Button type="primary" class="ml-16px" onClick={onShare} disabled={!selectedRows.value.length}>
|
||||
分享
|
||||
</Button>
|
||||
</div>
|
||||
@ -176,109 +159,99 @@ export default {
|
||||
</div>
|
||||
<Table
|
||||
ref={tableRef}
|
||||
data={dataSource.value}
|
||||
row-key="id"
|
||||
column-resizable
|
||||
row-selection={rowSelection.value}
|
||||
selected-keys={selectedRowKeys.value}
|
||||
dataSource={dataSource.value}
|
||||
rowKey="id"
|
||||
rowSelection={{
|
||||
selectedRowKeys: selectedRowKeys.value,
|
||||
onSelect: handleSelect,
|
||||
onSelectAll: handleSelectAll,
|
||||
}}
|
||||
pagination={false}
|
||||
scroll={{ x: '100%', y: '100%' }}
|
||||
class="overflow-hidden"
|
||||
bordered
|
||||
onSorterChange={handleSorterChange}
|
||||
onSelect={handleSelect}
|
||||
onSelectAll={handleSelectAll}
|
||||
showSorterTooltip={false}
|
||||
onChange={handleSorterChange}
|
||||
v-slots={{
|
||||
empty: () => <NoData />,
|
||||
columns: () => (
|
||||
<>
|
||||
{TABLE_COLUMNS.map((column) => (
|
||||
<TableColumn
|
||||
key={column.dataIndex}
|
||||
data-index={column.dataIndex}
|
||||
fixed={column.fixed}
|
||||
width={column.width}
|
||||
min-width={column.minWidth}
|
||||
sortable={column.sortable}
|
||||
align={column.align}
|
||||
ellipsis
|
||||
tooltip
|
||||
v-slots={{
|
||||
title: () => (
|
||||
<div class="flex items-center">
|
||||
<span class="cts mr-4px bold color-#211F24">{column.title}</span>
|
||||
{column.tooltip && (
|
||||
<Tooltip content={column.tooltip} position="top">
|
||||
<IconQuestionCircle class="tooltip-icon color-#737478" size={16} />
|
||||
</Tooltip>
|
||||
)}
|
||||
</div>
|
||||
),
|
||||
cell: ({ record }) => {
|
||||
if (column.dataIndex === 'audit_status') {
|
||||
return (
|
||||
<div
|
||||
class="flex items-center w-fit h-24px px-8px rounded-2px"
|
||||
style={{ backgroundColor: getStatusInfo(record.audit_status).backgroundColor }}
|
||||
>
|
||||
<span class="cts s1 bold" style={{ color: getStatusInfo(record.audit_status).color }}>
|
||||
{getStatusInfo(record.audit_status).name}
|
||||
</span>
|
||||
</div>
|
||||
);
|
||||
} else if (column.dataIndex === 'title') {
|
||||
return <TextOverTips context={record.title} />;
|
||||
} else if (column.dataIndex === 'type') {
|
||||
return (
|
||||
<div class="flex items-center">
|
||||
<img
|
||||
src={record.type === EnumManuscriptType.Image ? icon2 : icon3}
|
||||
width="16"
|
||||
height="16"
|
||||
class="mr-4px"
|
||||
/>
|
||||
<span
|
||||
class={`cts !text-14px !lh-22px ${
|
||||
record.type === EnumManuscriptType.Image ? '!color-#25C883' : '!color-#6D4CFE'
|
||||
}`}
|
||||
>
|
||||
{record.type === EnumManuscriptType.Image ? '图文' : '视频'}
|
||||
</span>
|
||||
</div>
|
||||
);
|
||||
} else if (column.dataIndex === 'last_modified_at') {
|
||||
return (
|
||||
<span class="cts num">
|
||||
{exactFormatTime(
|
||||
record.last_modified_at,
|
||||
'YYYY-MM-DD HH:mm:ss',
|
||||
'YYYY-MM-DD HH:mm:ss',
|
||||
)}
|
||||
</span>
|
||||
);
|
||||
} else {
|
||||
return formatTableField(column, record, true);
|
||||
}
|
||||
},
|
||||
}}
|
||||
/>
|
||||
))}
|
||||
</>
|
||||
),
|
||||
emptyText: () => <NoData />,
|
||||
}}
|
||||
/>
|
||||
>
|
||||
{TABLE_COLUMNS.map((column) => (
|
||||
<Table.Column
|
||||
key={column.dataIndex}
|
||||
dataIndex={column.dataIndex}
|
||||
fixed={column.fixed}
|
||||
width={column.width}
|
||||
minWidth={column.minWidth}
|
||||
sorter={column.sortable}
|
||||
align={column.align}
|
||||
ellipsis
|
||||
title={() => (
|
||||
<>
|
||||
<span class="cts mr-4px bold color-#211F24">{column.title}</span>
|
||||
{column.tooltip && (
|
||||
<Tooltip title={column.tooltip} placement="top">
|
||||
<IconQuestionCircle class="tooltip-icon color-#737478" size={16} />
|
||||
</Tooltip>
|
||||
)}
|
||||
</>
|
||||
)}
|
||||
customRender={({ record }) => {
|
||||
if (column.dataIndex === 'audit_status') {
|
||||
return (
|
||||
<div
|
||||
class="flex items-center w-fit h-24px px-8px rounded-2px"
|
||||
style={{ backgroundColor: getStatusInfo(record.audit_status).backgroundColor }}
|
||||
>
|
||||
<span class="cts s1 bold" style={{ color: getStatusInfo(record.audit_status).color }}>
|
||||
{getStatusInfo(record.audit_status).name}
|
||||
</span>
|
||||
</div>
|
||||
);
|
||||
} else if (column.dataIndex === 'title') {
|
||||
return <TextOverTips context={record.title} class="!text-12px" />;
|
||||
} else if (column.dataIndex === 'type') {
|
||||
return (
|
||||
<div class="flex items-center">
|
||||
<img
|
||||
src={record.type === EnumManuscriptType.Image ? icon2 : icon3}
|
||||
width="16"
|
||||
height="16"
|
||||
class="mr-4px"
|
||||
/>
|
||||
<span
|
||||
class={`cts !text-14px !lh-22px ${
|
||||
record.type === EnumManuscriptType.Image ? '!color-#25C883' : '!color-#6D4CFE'
|
||||
}`}
|
||||
>
|
||||
{record.type === EnumManuscriptType.Image ? '图文' : '视频'}
|
||||
</span>
|
||||
</div>
|
||||
);
|
||||
} else if (column.dataIndex === 'last_modified_at') {
|
||||
return (
|
||||
<span class="cts num">
|
||||
{exactFormatTime(record.last_modified_at, 'YYYY-MM-DD HH:mm:ss', 'YYYY-MM-DD HH:mm:ss')}
|
||||
</span>
|
||||
);
|
||||
} else {
|
||||
return formatTableField(column, record, true);
|
||||
}
|
||||
}}
|
||||
/>
|
||||
))}
|
||||
</Table>
|
||||
{pageInfo.value.total > 0 && (
|
||||
<div class="flex justify-end mt-16px">
|
||||
<Pagination
|
||||
total={pageInfo.value.total}
|
||||
size="mini"
|
||||
show-total
|
||||
show-jumper
|
||||
show-page-size
|
||||
size="small"
|
||||
showTotal={(total, range) => `共 ${total} 条`}
|
||||
showQuickJumper
|
||||
showSizeChanger
|
||||
current={pageInfo.value.page}
|
||||
page-size={pageInfo.value.page_size}
|
||||
pageSize={pageInfo.value.page_size}
|
||||
onChange={onPageChange}
|
||||
onPageSizeChange={onPageSizeChange}
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
<script lang="jsx">
|
||||
import { Modal, Form, FormItem, Input, Button, Message as AMessage } from '@arco-design/web-vue';
|
||||
import { Button, Modal, Form, FormItem, Input, Tooltip, message } from 'ant-design-vue';
|
||||
import CommonSelect from '@/components/common-select';
|
||||
|
||||
import { useClipboard } from '@vueuse/core';
|
||||
@ -65,24 +65,22 @@ export default {
|
||||
};
|
||||
|
||||
const onGenerateLink = () => {
|
||||
formRef.value.validate().then(async (errors) => {
|
||||
if (!errors) {
|
||||
try {
|
||||
loading.value = true;
|
||||
const { code, data } = await postShareLinksGenerate(formData.value);
|
||||
if (code === 200) {
|
||||
onClose();
|
||||
formRef.value.validate().then(async () => {
|
||||
try {
|
||||
loading.value = true;
|
||||
const { code, data } = await postShareLinksGenerate(formData.value);
|
||||
if (code === 200) {
|
||||
onClose();
|
||||
|
||||
const url = router.resolve({
|
||||
path: `/explore/list/${data.code}`,
|
||||
}).href;
|
||||
copy(generateFullUrl(url));
|
||||
AMessage.success('链接已复制!');
|
||||
emit('close');
|
||||
}
|
||||
} finally {
|
||||
loading.value = false;
|
||||
const url = router.resolve({
|
||||
path: `/explore/list/${data.code}`,
|
||||
}).href;
|
||||
copy(generateFullUrl(url));
|
||||
message.success('链接已复制!');
|
||||
emit('close');
|
||||
}
|
||||
} finally {
|
||||
loading.value = false;
|
||||
}
|
||||
});
|
||||
};
|
||||
@ -96,27 +94,33 @@ export default {
|
||||
});
|
||||
return () => (
|
||||
<Modal
|
||||
v-model:visible={visible.value}
|
||||
v-model:open={visible.value}
|
||||
title="分享内容稿件"
|
||||
width="480px"
|
||||
onClose={onClose}
|
||||
unmount-on-close
|
||||
onCancel={onClose}
|
||||
destroyOnClose
|
||||
centered
|
||||
auto-label-width
|
||||
v-slots={{
|
||||
footer: () => (
|
||||
<>
|
||||
<Button size="medium" onClick={onClose}>
|
||||
取消
|
||||
</Button>
|
||||
<Button type="primary" class="ml-16px" size="medium" onClick={onGenerateLink} disabled={loading.value}>
|
||||
<Button onClick={onClose}>取消</Button>
|
||||
<Button type="primary" class="ml-16px" onClick={onGenerateLink} disabled={loading.value}>
|
||||
{loading.value ? '生成中...' : '生成链接'}
|
||||
</Button>
|
||||
</>
|
||||
),
|
||||
}}
|
||||
>
|
||||
<Form ref={formRef} rules={rules} model={formData.value} auto-label-width>
|
||||
<FormItem label="有效期" prop="days" row-class="!items-center">
|
||||
<Form
|
||||
ref={formRef}
|
||||
rules={rules}
|
||||
model={formData.value}
|
||||
labelAlign="right"
|
||||
labelCol={{ span: 5 }}
|
||||
wrapperCol={{ span: 19 }}
|
||||
>
|
||||
<FormItem label="有效期" name="days" row-class="!items-center">
|
||||
<CommonSelect
|
||||
v-model={formData.value.days}
|
||||
options={OPTIONS}
|
||||
@ -128,21 +132,20 @@ export default {
|
||||
/>
|
||||
</FormItem>
|
||||
<FormItem
|
||||
label="分享对象"
|
||||
prop="receiver"
|
||||
name="receiver"
|
||||
row-class="!items-center"
|
||||
v-slots={{
|
||||
label: () => (
|
||||
<div class="flex items-center">
|
||||
<span>分享对象</span>
|
||||
<a-tooltip content="可填写客户名称、昵称等,非必填" position="top">
|
||||
<Tooltip title="可填写客户名称、昵称等,非必填" placement="top">
|
||||
<icon-question-circle class="tooltip-icon color-#737478 ml-4px" size="14" />
|
||||
</a-tooltip>
|
||||
</Tooltip>
|
||||
</div>
|
||||
),
|
||||
}}
|
||||
>
|
||||
<Input v-model={formData.value.receiver} class="!w-240px" size="large" placeholder="请输入分享对象" />
|
||||
<Input v-model:value={formData.value.receiver} class="!w-240px" size="large" placeholder="请输入分享对象" />
|
||||
</FormItem>
|
||||
</Form>
|
||||
</Modal>
|
||||
|
||||
@ -18,49 +18,36 @@
|
||||
font-size: 14px;
|
||||
}
|
||||
}
|
||||
.arco-modal-body {
|
||||
.ant-modal-body {
|
||||
height: 464px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
overflow: hidden;
|
||||
.arco-scrollbar-track {
|
||||
.ant-scrollbar-track {
|
||||
display: none !important;
|
||||
}
|
||||
.arco-table {
|
||||
.arco-table-container {
|
||||
.arco-table-element {
|
||||
thead {
|
||||
.arco-table-tr {
|
||||
.arco-table-th {
|
||||
.arco-table-cell {
|
||||
padding: 10px 16px !important;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
tbody {
|
||||
.arco-table-tr {
|
||||
.arco-table-td {
|
||||
.arco-table-cell {
|
||||
padding: 6px 16px;
|
||||
.arco-table-cell-content,
|
||||
.arco-table-td-content {
|
||||
font-size: 12px;
|
||||
line-height: 20px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
.ant-table {
|
||||
.ant-table-thead {
|
||||
.ant-table-cell {
|
||||
padding: 10px 16px !important;
|
||||
}
|
||||
}
|
||||
.ant-table-body {
|
||||
.ant-table-cell {
|
||||
padding: 6px 16px !important;
|
||||
.ant-table-cell-content {
|
||||
font-size: 12px;
|
||||
line-height: 20px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
.arco-pagination {
|
||||
.arco-pagination-total,
|
||||
.arco-pagination-jumper-prepend {
|
||||
.ant-pagination {
|
||||
.ant-pagination-total-text,
|
||||
.ant-pagination-options-quick-jumper {
|
||||
font-size: 14px;
|
||||
}
|
||||
.arco-pagination-jumper-prepend {
|
||||
.ant-pagination-options-quick-jumper {
|
||||
font-family: $font-family-regular;
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,16 +1,5 @@
|
||||
<script lang="jsx">
|
||||
import {
|
||||
Modal,
|
||||
Form,
|
||||
FormItem,
|
||||
Input,
|
||||
RadioGroup,
|
||||
Radio,
|
||||
Upload,
|
||||
Button,
|
||||
Message as AMessage,
|
||||
Textarea,
|
||||
} from '@arco-design/web-vue';
|
||||
import { Modal, Button, Form, FormItem, RadioGroup, Radio, Input, message, Upload } from 'ant-design-vue';
|
||||
import { useClipboard } from '@vueuse/core';
|
||||
import { getWriterLinksGenerate, getTemplateUrl, postWorksByLink, postWorksByFile } from '@/api/all/generationWorkshop';
|
||||
import { generateFullUrl } from '@/utils/tools';
|
||||
@ -18,6 +7,9 @@ import { slsWithCatch } from '@/utils/stroage.ts';
|
||||
|
||||
import TextOverTips from '@/components/text-over-tips';
|
||||
import icon1 from '@/assets/img/media-account/icon-feedback-fail.png';
|
||||
import icon2 from '@/assets/img/media-account/icon-download.png';
|
||||
|
||||
const { TextArea } = Input;
|
||||
|
||||
// 状态枚举
|
||||
const TASK_STATUS = {
|
||||
@ -41,7 +33,7 @@ const INITIAL_FORM = {
|
||||
|
||||
export default {
|
||||
setup(props, { emit, expose }) {
|
||||
const update = inject('update');
|
||||
// const update = inject('update');
|
||||
const router = useRouter();
|
||||
|
||||
// 响应式状态
|
||||
@ -119,15 +111,13 @@ export default {
|
||||
handleHandwriteSubmit();
|
||||
return;
|
||||
}
|
||||
formRef.value?.validate(async (errors) => {
|
||||
if (!errors) {
|
||||
taskStatus.value = TASK_STATUS.LOADING;
|
||||
const { link } = form.value;
|
||||
const { code, data } = await postWorksByLink({ link });
|
||||
if (code === 200) {
|
||||
taskStatus.value = TASK_STATUS.SUCCESS;
|
||||
works.value = data ? [data] : [];
|
||||
}
|
||||
formRef.value?.validate().then(async () => {
|
||||
taskStatus.value = TASK_STATUS.LOADING;
|
||||
const { link } = form.value;
|
||||
const { code, data } = await postWorksByLink({ link });
|
||||
if (code === 200) {
|
||||
taskStatus.value = TASK_STATUS.SUCCESS;
|
||||
works.value = data ? [data] : [];
|
||||
}
|
||||
});
|
||||
}, 300);
|
||||
@ -140,27 +130,25 @@ export default {
|
||||
// 手写提交处理
|
||||
const handleHandwriteSubmit = () => {
|
||||
if (!form.value.writerLink) {
|
||||
AMessage.warning('请输入上传链接!');
|
||||
message.warning('请输入上传链接!');
|
||||
return;
|
||||
}
|
||||
|
||||
copy(form.value.writerLink);
|
||||
AMessage.success('复制成功!');
|
||||
message.success('复制成功!');
|
||||
onClose();
|
||||
};
|
||||
|
||||
// 取消上传
|
||||
const onCancelUpload = () => {
|
||||
taskStatus.value = TASK_STATUS.DEFAULT;
|
||||
AMessage.info('已取消上传');
|
||||
message.info('已取消上传');
|
||||
};
|
||||
|
||||
// 文件上传处理
|
||||
const handleUpload = async (option) => {
|
||||
taskStatus.value = TASK_STATUS.LOADING;
|
||||
const {
|
||||
fileItem: { file },
|
||||
} = option;
|
||||
const { file } = option;
|
||||
|
||||
const formData = new FormData();
|
||||
formData.append('file', file);
|
||||
@ -222,9 +210,9 @@ export default {
|
||||
|
||||
// 渲染链接上传表单
|
||||
const renderLinkForm = () => (
|
||||
<FormItem label="链接地址" field="link" required>
|
||||
<Textarea
|
||||
v-model={form.value.link}
|
||||
<FormItem label="链接地址" name="link" required>
|
||||
<TextArea
|
||||
v-model:value={form.value.link}
|
||||
size="large"
|
||||
placeholder="请输入飞书链接地址"
|
||||
autoSize={{ minRows: 5, maxRows: 8 }}
|
||||
@ -234,8 +222,8 @@ export default {
|
||||
|
||||
// 渲染手写上传表单
|
||||
const renderHandwriteForm = () => (
|
||||
<FormItem label="上传链接" field="writerLink">
|
||||
<Input v-model={form.value.writerLink} placeholder="请输入上传链接" disabled size="large" />
|
||||
<FormItem label="上传链接" name="writerLink">
|
||||
<Input v-model:value={form.value.writerLink} placeholder="请输入上传链接" disabled size="large" />
|
||||
</FormItem>
|
||||
);
|
||||
|
||||
@ -245,24 +233,20 @@ export default {
|
||||
<div class="flex flex-col w-full">
|
||||
<Upload
|
||||
action="/"
|
||||
draggable
|
||||
multiple
|
||||
customRequest={handleUpload}
|
||||
class="w-full"
|
||||
accept=".xlsx,.xls,.docx,.doc,.mp4,.mov,.avi,.flv,.wmv,.m4v"
|
||||
show-file-list={false}
|
||||
showUploadList={false}
|
||||
>
|
||||
{{
|
||||
'upload-button': () => (
|
||||
<div class="upload-box">
|
||||
<icon-plus size="14" class="mb-16px" />
|
||||
<span class="text mb-4px">点击或拖拽文件到此处上传</span>
|
||||
<span class="tip">支持文档(文本+图), 视频批量上传</span>
|
||||
</div>
|
||||
),
|
||||
}}
|
||||
<div class="upload-box">
|
||||
<icon-plus size="14" class="mb-16px" />
|
||||
<span class="text mb-4px">点击或拖拽文件到此处上传</span>
|
||||
<span class="tip">支持文档(文本+图), 视频批量上传</span>
|
||||
</div>
|
||||
</Upload>
|
||||
<div class="flex items-center cursor-pointer mt-8px" onClick={handleDownloadTemplate}>
|
||||
<icon-download size="14" class="mr-4px !color-#6D4CFE" />
|
||||
<img src={icon2} width="16" height="16" class="mr-4px" />
|
||||
<span class="cts color-#6D4CFE">下载示例文档</span>
|
||||
</div>
|
||||
</div>
|
||||
@ -332,36 +316,30 @@ export default {
|
||||
const renderFooterButtons = () => {
|
||||
const buttonMap = {
|
||||
[TASK_STATUS.LOADING]: () => (
|
||||
<Button type="primary" size="medium" onClick={onCancelUpload}>
|
||||
<Button type="primary" onClick={onCancelUpload}>
|
||||
取消上传
|
||||
</Button>
|
||||
),
|
||||
[TASK_STATUS.DEFAULT]: () => (
|
||||
<>
|
||||
<Button size="medium" onClick={onClose}>
|
||||
取消
|
||||
</Button>
|
||||
<Button type="primary" size="medium" onClick={onSubmit}>
|
||||
<Button onClick={onClose}>取消</Button>
|
||||
<Button type="primary" onClick={onSubmit}>
|
||||
{isHandwrite.value ? '复制链接' : '确认'}
|
||||
</Button>
|
||||
</>
|
||||
),
|
||||
[TASK_STATUS.FAILED]: () => (
|
||||
<>
|
||||
<Button size="medium" onClick={onClose}>
|
||||
取消
|
||||
</Button>
|
||||
<Button type="primary" size="medium" onClick={onClose}>
|
||||
<Button onClick={onClose}>取消</Button>
|
||||
<Button type="primary" onClick={onClose}>
|
||||
重新上传
|
||||
</Button>
|
||||
</>
|
||||
),
|
||||
[TASK_STATUS.SUCCESS]: () => (
|
||||
<>
|
||||
<Button size="medium" onClick={onClose}>
|
||||
取消
|
||||
</Button>
|
||||
<Button type="primary" size="medium" onClick={goUpload}>
|
||||
<Button onClick={onClose}>取消</Button>
|
||||
<Button type="primary" onClick={goUpload}>
|
||||
确认
|
||||
</Button>
|
||||
</>
|
||||
@ -375,17 +353,16 @@ export default {
|
||||
|
||||
return () => (
|
||||
<Modal
|
||||
v-model:visible={visible.value}
|
||||
centered
|
||||
v-model:open={visible.value}
|
||||
title={getTitle()}
|
||||
modal-class="upload-manuscript-modal"
|
||||
wrapClassName="upload-manuscript-modal"
|
||||
width="500px"
|
||||
mask-closable={false}
|
||||
unmount-on-close
|
||||
onClose={onClose}
|
||||
footer={!(isDefault.value && isLocal.value)}
|
||||
v-slots={{
|
||||
footer: () => renderFooterButtons(),
|
||||
}}
|
||||
maskClosable={false}
|
||||
destroyOnClose
|
||||
centered
|
||||
onCancel={onClose}
|
||||
footer={isDefault.value && isLocal.value ? null : renderFooterButtons()}
|
||||
>
|
||||
<Form
|
||||
ref={formRef}
|
||||
@ -398,7 +375,7 @@ export default {
|
||||
>
|
||||
{isDefault.value && (
|
||||
<FormItem label="上传方式">
|
||||
<RadioGroup v-model={uploadType.value} onChange={onUploadTypeChange}>
|
||||
<RadioGroup v-model:value={uploadType.value} onChange={onUploadTypeChange}>
|
||||
<Radio value={UPLOAD_TYPE.LINK}>链接上传</Radio>
|
||||
<Radio value={UPLOAD_TYPE.LOCAL}>本地上传</Radio>
|
||||
<Radio value={UPLOAD_TYPE.HANDWRITE}>写手上传</Radio>
|
||||
|
||||
@ -28,4 +28,8 @@
|
||||
border: 1px dashed var(--Border-1, #d7d7d9);
|
||||
background: var(--BG-200, #f2f3f5);
|
||||
}
|
||||
.ant-upload {
|
||||
cursor: pointer;
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
<script lang="jsx">
|
||||
import { Button, Message as AMessage, Spin } from '@arco-design/web-vue';
|
||||
import { Button, Spin, message } from 'ant-design-vue';
|
||||
|
||||
import { useRouter, useRoute } from 'vue-router';
|
||||
import { AuditStatus } from '@/views/material-center/components/finished-products/constants';
|
||||
@ -119,12 +119,12 @@ export default {
|
||||
|
||||
return (
|
||||
<>
|
||||
<Button size="medium" type="outline" class="mr-12px" onClick={onBack}>
|
||||
<Button type="primary" ghost class="mr-12px" onClick={onBack}>
|
||||
退出
|
||||
</Button>
|
||||
<Button
|
||||
size="medium"
|
||||
type="outline"
|
||||
type="primary"
|
||||
ghost
|
||||
class="mr-12px"
|
||||
onClick={() =>
|
||||
router.push({
|
||||
@ -138,7 +138,7 @@ export default {
|
||||
编辑
|
||||
</Button>
|
||||
{audit_status !== AuditStatus.Passed && (
|
||||
<Button type="primary" size="medium" onClick={_fn}>
|
||||
<Button type="primary" onClick={_fn}>
|
||||
去审核
|
||||
</Button>
|
||||
)}
|
||||
@ -157,7 +157,7 @@ export default {
|
||||
});
|
||||
|
||||
return () => (
|
||||
<Spin loading={loading.value} class="manuscript-detail-wrap" size={50}>
|
||||
<Spin spinning={loading.value} wrapperClassName="manuscript-detail-wrap" size="large">
|
||||
<div class="h-full w-full flex flex-col">
|
||||
<div class="flex items-center mb-8px">
|
||||
<span class="cts color-#4E5969 cursor-pointer" onClick={onBack}>
|
||||
|
||||
@ -1,18 +1,19 @@
|
||||
<template>
|
||||
<a-modal v-model:visible="visible" title="退出编辑" width="480px" @close="onClose">
|
||||
<Modal v-model:open="visible" title="退出编辑" centered width="480px" @cancel="onClose">
|
||||
<div class="flex items-center">
|
||||
<img :src="icon1" width="20" height="20" class="mr-12px" />
|
||||
<span>内容已修改尚未保存,若退出编辑,本次修改将不保存。</span>
|
||||
</div>
|
||||
<template #footer>
|
||||
<a-button size="medium" @click="onClose">继续编辑</a-button>
|
||||
<a-button type="primary" class="ml-8px" size="medium" @click="onConfirm">确认退出</a-button>
|
||||
<Button size="medium" @click="onClose">继续编辑</Button>
|
||||
<Button type="primary" class="ml-8px" size="medium" @click="onConfirm">确认退出</Button>
|
||||
</template>
|
||||
</a-modal>
|
||||
</Modal>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref } from 'vue';
|
||||
import { Button, Modal } from 'ant-design-vue';
|
||||
import icon1 from '@/assets/img/media-account/icon-warn-1.png';
|
||||
|
||||
const router = useRouter();
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
<script lang="jsx">
|
||||
import { Button, Message as AMessage } from '@arco-design/web-vue';
|
||||
import { Button, message } from 'ant-design-vue';
|
||||
import EditForm, { ENUM_UPLOAD_STATUS, INITIAL_VIDEO_INFO } from '../components/edit-form';
|
||||
import CancelEditModal from './cancel-edit-modal.vue';
|
||||
|
||||
@ -43,14 +43,14 @@ export default {
|
||||
const onSave = async (check = false) => {
|
||||
formRef.value?.validate().then(async () => {
|
||||
if (dataSource.value.videoInfo.uploadStatus === ENUM_UPLOAD_STATUS.UPLOADING) {
|
||||
AMessage.warning('有视频正在上传中,请等待上传完成后再提交');
|
||||
message.warning('有视频正在上传中,请等待上传完成后再提交');
|
||||
return;
|
||||
}
|
||||
|
||||
const filteredWorks = omit(dataSource.value, 'videoInfo');
|
||||
const { code, data } = await putWorksUpdate({ id: workId.value, ...filteredWorks });
|
||||
if (code === 200) {
|
||||
AMessage.success('保存成功');
|
||||
message.success('保存成功');
|
||||
isSaved.value = true;
|
||||
|
||||
if (check) {
|
||||
|
||||
@ -3,18 +3,17 @@
|
||||
<div class="filter-row">
|
||||
<div class="filter-row-item">
|
||||
<span class="label">内容稿件标题</span>
|
||||
<a-input
|
||||
v-model="query.title"
|
||||
<Input
|
||||
v-model:value="query.title"
|
||||
class="!w-240px"
|
||||
placeholder="请输入内容稿件标题"
|
||||
size="medium"
|
||||
allow-clear
|
||||
allowClear
|
||||
@change="handleSearch"
|
||||
>
|
||||
<template #prefix>
|
||||
<icon-search />
|
||||
</template>
|
||||
</a-input>
|
||||
</Input>
|
||||
</div>
|
||||
<!-- <div class="filter-row-item">
|
||||
<span class="label">所属项目</span>
|
||||
@ -28,20 +27,17 @@
|
||||
</div> -->
|
||||
<div class="filter-row-item">
|
||||
<span class="label">序号</span>
|
||||
<a-space size="medium">
|
||||
<a-input
|
||||
v-model="query.uid"
|
||||
class="!w-160px"
|
||||
placeholder="请输入序号"
|
||||
size="medium"
|
||||
allow-clear
|
||||
@change="handleSearch"
|
||||
>
|
||||
<template #prefix>
|
||||
<icon-search />
|
||||
</template>
|
||||
</a-input>
|
||||
</a-space>
|
||||
<Input
|
||||
v-model:value="query.uid"
|
||||
class="!w-160px"
|
||||
placeholder="请输入序号"
|
||||
allowClear
|
||||
@change="handleSearch"
|
||||
>
|
||||
<template #prefix>
|
||||
<icon-search />
|
||||
</template>
|
||||
</Input>
|
||||
</div>
|
||||
<div class="filter-row-item">
|
||||
<span class="label">审核状态</span>
|
||||
@ -56,8 +52,8 @@
|
||||
</div>
|
||||
<div class="filter-row-item">
|
||||
<span class="label">上传时间</span>
|
||||
<a-range-picker
|
||||
v-model="created_at"
|
||||
<DatePicker.RangePicker
|
||||
v-model:value="created_at"
|
||||
size="medium"
|
||||
allow-clear
|
||||
format="YYYY-MM-DD"
|
||||
@ -66,24 +62,25 @@
|
||||
/>
|
||||
</div>
|
||||
<div class="filter-row-item">
|
||||
<a-button type="outline" class="mr-12px" size="medium" @click="handleSearch">
|
||||
<Button type="primary" ghost class="mr-12px" size="medium" @click="handleSearch">
|
||||
<template #icon>
|
||||
<icon-search />
|
||||
<icon-search class="mr-8px" />
|
||||
</template>
|
||||
<template #default>搜索</template>
|
||||
</a-button>
|
||||
<a-button size="medium" @click="handleReset">
|
||||
</Button>
|
||||
<Button size="medium" @click="handleReset">
|
||||
<template #icon>
|
||||
<icon-refresh />
|
||||
<icon-refresh class="mr-8px" />
|
||||
</template>
|
||||
<template #default>重置</template>
|
||||
</a-button>
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { Button, Input, DatePicker } from 'ant-design-vue';
|
||||
import { defineEmits, defineProps } from 'vue';
|
||||
import { CHECK_STATUS } from '@/views/material-center/components/finished-products/manuscript/list/constants';
|
||||
import CommonSelect from '@/components/common-select';
|
||||
@ -96,7 +93,7 @@ const props = defineProps({
|
||||
},
|
||||
});
|
||||
|
||||
const emits = defineEmits('search', 'reset', 'update:query');
|
||||
const emits = defineEmits(['search', 'reset', 'update:query']);
|
||||
|
||||
const created_at = ref([]);
|
||||
// const projects = ref([]);
|
||||
|
||||
@ -67,7 +67,7 @@ export const TABLE_COLUMNS = [
|
||||
{
|
||||
title: '操作',
|
||||
dataIndex: 'operation',
|
||||
width: 180,
|
||||
width: 200,
|
||||
fixed: 'right',
|
||||
},
|
||||
];
|
||||
|
||||
@ -1,25 +1,19 @@
|
||||
<template>
|
||||
<a-modal
|
||||
v-model:visible="visible"
|
||||
title="删除稿件"
|
||||
width="480px"
|
||||
@close="onClose"
|
||||
>
|
||||
<Modal v-model:open="visible" title="删除稿件" centered width="480px" @cancel="onClose">
|
||||
<div class="flex items-center">
|
||||
<img :src="icon1" width="20" height="20" class="mr-12px" />
|
||||
<span>确认删除 {{ projectName }} 这个稿件吗?</span>
|
||||
<span>确认删除 {{ projectName }} 这个稿件吗?</span>
|
||||
</div>
|
||||
<template #footer>
|
||||
<a-button size="large" @click="onClose">取消</a-button>
|
||||
<a-button type="primary" class="ml-16px" status="danger" size="large" @click="onDelete"
|
||||
>确认删除</a-button
|
||||
>
|
||||
<Button size="large" @click="onClose">取消</Button>
|
||||
<Button type="primary" class="ml-16px" danger size="large" @click="onDelete">确认删除</Button>
|
||||
</template>
|
||||
</a-modal>
|
||||
</Modal>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref } from 'vue';
|
||||
import { Button, Modal, message } from 'ant-design-vue';
|
||||
import { deleteWork } from '@/api/all/generationWorkshop';
|
||||
import icon1 from '@/assets/img/media-account/icon-warn-1.png';
|
||||
|
||||
@ -48,8 +42,8 @@ const open = (record) => {
|
||||
async function onDelete() {
|
||||
const { code } = await deleteWork(projectId.value);
|
||||
if (code === 200) {
|
||||
AMessage.success('删除成功');
|
||||
update()
|
||||
message.success('删除成功');
|
||||
update();
|
||||
onClose();
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,123 +1,114 @@
|
||||
<template>
|
||||
<a-table
|
||||
<Table
|
||||
ref="tableRef"
|
||||
:data="dataSource"
|
||||
row-key="id"
|
||||
column-resizable
|
||||
:dataSource="dataSource"
|
||||
rowKey="id"
|
||||
:pagination="false"
|
||||
:scroll="{ x: '100%' }"
|
||||
class="manuscript-table w-100% flex-1"
|
||||
bordered
|
||||
@sorter-change="handleSorterChange"
|
||||
:showSorterTooltip="false"
|
||||
@change="handleTableChange"
|
||||
>
|
||||
<template #empty>
|
||||
<template #emptyText>
|
||||
<NoData text="暂无稿件" />
|
||||
</template>
|
||||
<template #columns>
|
||||
<a-table-column
|
||||
v-for="column in TABLE_COLUMNS"
|
||||
:key="column.dataIndex"
|
||||
:data-index="column.dataIndex"
|
||||
:fixed="column.fixed"
|
||||
:width="column.width"
|
||||
:min-width="column.minWidth"
|
||||
:sortable="column.sortable"
|
||||
:align="column.align"
|
||||
ellipsis
|
||||
tooltip
|
||||
>
|
||||
<template #title>
|
||||
<div class="flex items-center">
|
||||
<span class="cts mr-4px">{{ column.title }}</span>
|
||||
<a-tooltip v-if="column.tooltip" :content="column.tooltip" position="top">
|
||||
<icon-question-circle class="tooltip-icon color-#737478" size="16" />
|
||||
</a-tooltip>
|
||||
</div>
|
||||
</template>
|
||||
<Column
|
||||
v-for="column in TABLE_COLUMNS"
|
||||
:key="column.dataIndex"
|
||||
:dataIndex="column.dataIndex"
|
||||
:fixed="column.fixed"
|
||||
:width="column.width"
|
||||
:minWidth="column.minWidth"
|
||||
:sorter="column.sortable"
|
||||
:align="column.align"
|
||||
:ellipsis="true"
|
||||
>
|
||||
<template #title>
|
||||
<span class="cts mr-4px">{{ column.title }}</span>
|
||||
<Tooltip v-if="column.tooltip" :title="column.tooltip" placement="top">
|
||||
<icon-question-circle class="tooltip-icon color-#737478" size="16" />
|
||||
</Tooltip>
|
||||
</template>
|
||||
|
||||
<template v-if="column.dataIndex === 'create_at'" #cell="{ record }">
|
||||
{{ exactFormatTime(record.create_at) }}
|
||||
</template>
|
||||
<template v-else-if="column.dataIndex === 'customer_opinion'" #cell="{ record }">
|
||||
<p
|
||||
class="h-28px px-8px flex items-center rounded-2px w-fit"
|
||||
:style="{ background: getCustomerOpinionInfo(record.customer_opinion)?.bg }"
|
||||
>
|
||||
<span class="cts" :class="getCustomerOpinionInfo(record.customer_opinion)?.color">{{
|
||||
getCustomerOpinionInfo(record.customer_opinion)?.label ?? '-'
|
||||
}}</span>
|
||||
</p>
|
||||
</template>
|
||||
<template v-else-if="column.dataIndex === 'title'" #cell="{ record }">
|
||||
<TextOverTips :context="record.title" :line="3" class="title" @click="onDetail(record)" />
|
||||
</template>
|
||||
<template v-else-if="column.dataIndex === 'audit_status'" #cell="{ record }">
|
||||
<div
|
||||
class="flex items-center w-fit h-28px px-8px rounded-2px"
|
||||
:style="{ backgroundColor: getStatusInfo(record.audit_status).backgroundColor }"
|
||||
>
|
||||
<span class="cts s1" :style="{ color: getStatusInfo(record.audit_status).color }">{{
|
||||
getStatusInfo(record.audit_status).name
|
||||
}}</span>
|
||||
</div>
|
||||
</template>
|
||||
<template v-else-if="column.dataIndex === 'type'" #cell="{ record }">
|
||||
<div class="flex items-center">
|
||||
<img
|
||||
:src="record.type === EnumManuscriptType.Image ? icon2 : icon3"
|
||||
width="16"
|
||||
height="16"
|
||||
class="mr-4px"
|
||||
/>
|
||||
<span class="cts" :class="record.type === EnumManuscriptType.Image ? '!color-#25C883' : '!color-#6D4CFE'">{{
|
||||
record.type === EnumManuscriptType.Image ? '图文' : '视频'
|
||||
}}</span>
|
||||
</div>
|
||||
</template>
|
||||
<template v-else-if="['uploader', 'last_modifier'].includes(column.dataIndex)" #cell="{ record }">
|
||||
{{ record[column.dataIndex].name || record[column.dataIndex].mobile }}
|
||||
</template>
|
||||
<template v-else-if="['created_at', 'last_modified_at'].includes(column.dataIndex)" #cell="{ record }">
|
||||
{{ exactFormatTime(record[column.dataIndex]) }}
|
||||
</template>
|
||||
<template v-else-if="column.dataIndex === 'cover'" #cell="{ record }">
|
||||
<HoverImagePreview :src="record.cover">
|
||||
<a-image :width="64" :height="64" :src="record.cover" class="!rounded-6px" fit="cover">
|
||||
<template #error>
|
||||
<img :src="icon4" class="w-full h-full" />
|
||||
</template>
|
||||
</a-image>
|
||||
</HoverImagePreview>
|
||||
</template>
|
||||
<template v-else-if="column.dataIndex === 'operation'" #cell="{ record }">
|
||||
<div class="flex items-center">
|
||||
<img class="mr-8px cursor-pointer" :src="icon1" width="14" height="14" @click="onDelete(record)" />
|
||||
<a-button type="outline" size="mini" class="mr-8px" @click="onEdit(record)">编辑</a-button>
|
||||
<a-button type="outline" size="mini" @click="onDetail(record)">详情</a-button>
|
||||
</div>
|
||||
</template>
|
||||
<template v-else #cell="{ record }">
|
||||
{{ formatTableField(column, record, true) }}
|
||||
</template>
|
||||
</a-table-column>
|
||||
</template>
|
||||
</a-table>
|
||||
<template v-if="column.dataIndex === 'create_at'" #customRender="{ record }">
|
||||
{{ exactFormatTime(record.create_at) }}
|
||||
</template>
|
||||
<template v-else-if="column.dataIndex === 'customer_opinion'" #customRender="{ record }">
|
||||
<p
|
||||
class="h-28px px-8px flex items-center rounded-2px w-fit"
|
||||
:style="{ background: getCustomerOpinionInfo(record.customer_opinion)?.bg }"
|
||||
>
|
||||
<span class="cts" :class="getCustomerOpinionInfo(record.customer_opinion)?.color">{{
|
||||
getCustomerOpinionInfo(record.customer_opinion)?.label ?? '-'
|
||||
}}</span>
|
||||
</p>
|
||||
</template>
|
||||
<template v-else-if="column.dataIndex === 'title'" #customRender="{ record }">
|
||||
<TextOverTips :context="record.title" :line="3" class="title" @click="onDetail(record)" />
|
||||
</template>
|
||||
<template v-else-if="column.dataIndex === 'audit_status'" #customRender="{ record }">
|
||||
<div
|
||||
class="flex items-center w-fit h-28px px-8px rounded-2px"
|
||||
:style="{ backgroundColor: getStatusInfo(record.audit_status).backgroundColor }"
|
||||
>
|
||||
<span class="cts s1" :style="{ color: getStatusInfo(record.audit_status).color }">{{
|
||||
getStatusInfo(record.audit_status).name
|
||||
}}</span>
|
||||
</div>
|
||||
</template>
|
||||
<template v-else-if="column.dataIndex === 'type'" #customRender="{ record }">
|
||||
<div class="flex items-center">
|
||||
<img :src="record.type === EnumManuscriptType.Image ? icon2 : icon3" width="16" height="16" class="mr-4px" />
|
||||
<span class="cts" :class="record.type === EnumManuscriptType.Image ? '!color-#25C883' : '!color-#6D4CFE'">{{
|
||||
record.type === EnumManuscriptType.Image ? '图文' : '视频'
|
||||
}}</span>
|
||||
</div>
|
||||
</template>
|
||||
<template v-else-if="['uploader', 'last_modifier'].includes(column.dataIndex)" #customRender="{ record }">
|
||||
{{ record[column.dataIndex].name || record[column.dataIndex].mobile }}
|
||||
</template>
|
||||
<template v-else-if="['created_at', 'last_modified_at'].includes(column.dataIndex)" #customRender="{ record }">
|
||||
{{ exactFormatTime(record[column.dataIndex]) }}
|
||||
</template>
|
||||
<template v-else-if="column.dataIndex === 'cover'" #customRender="{ record }">
|
||||
<HoverImagePreview :src="record.cover">
|
||||
<ImgLazyLoad :width="64" :height="64" :src="record.cover" class="!rounded-6px" />
|
||||
</HoverImagePreview>
|
||||
</template>
|
||||
<template v-else-if="column.dataIndex === 'operation'" #customRender="{ record }">
|
||||
<div class="flex items-center">
|
||||
<img class="mr-8px cursor-pointer" :src="icon1" width="14" height="14" @click="onDelete(record)" />
|
||||
<Button type="primary" ghost size="small" class="mr-8px" @click="onEdit(record)">编辑</Button>
|
||||
<Button type="primary" ghost size="small" @click="onDetail(record)">详情</Button>
|
||||
</div>
|
||||
</template>
|
||||
<template v-else #customRender="{ record }">
|
||||
{{ formatTableField(column, record, true) }}
|
||||
</template>
|
||||
</Column>
|
||||
</Table>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref } from 'vue';
|
||||
import { Button, Tooltip, Table, Image } from 'ant-design-vue';
|
||||
const { Column } = Table;
|
||||
import { formatTableField, exactFormatTime } from '@/utils/tools';
|
||||
import { TABLE_COLUMNS } from './constants';
|
||||
import { CHECK_STATUS, EnumManuscriptType } from '@/views/material-center/components/finished-products/manuscript/list/constants';
|
||||
import {
|
||||
CHECK_STATUS,
|
||||
EnumManuscriptType,
|
||||
} from '@/views/material-center/components/finished-products/manuscript/list/constants';
|
||||
import { CUSTOMER_OPINION } from '@/views/material-center/components/finished-products/manuscript/check-list/constants';
|
||||
|
||||
import TextOverTips from '@/components/text-over-tips';
|
||||
import HoverImagePreview from '@/components/hover-image-preview';
|
||||
import ImgLazyLoad from "@/components/img-lazy-load";
|
||||
|
||||
import icon1 from '@/assets/img/media-account/icon-delete.png';
|
||||
import icon2 from '@/assets/img/creative-generation-workshop/icon-photo.png';
|
||||
import icon3 from '@/assets/img/creative-generation-workshop/icon-video.png';
|
||||
import icon4 from '@/assets/img/error-img.png';
|
||||
|
||||
const emits = defineEmits(['edit', 'sorterChange', 'delete']);
|
||||
const router = useRouter();
|
||||
@ -131,8 +122,10 @@ const props = defineProps({
|
||||
|
||||
const tableRef = ref(null);
|
||||
|
||||
const handleSorterChange = (column, order) => {
|
||||
emits('sorterChange', column, order === 'ascend' ? 'asc' : 'desc');
|
||||
const handleTableChange = (pagination, filters, sorter) => {
|
||||
if (sorter && sorter.field) {
|
||||
emits('sorterChange', sorter.field, sorter.order === 'ascend' ? 'asc' : 'desc');
|
||||
}
|
||||
};
|
||||
const onDelete = (item) => {
|
||||
emits('delete', item);
|
||||
|
||||
@ -2,7 +2,7 @@ export const INITIAL_QUERY = {
|
||||
title: '',
|
||||
// project_ids: [],
|
||||
uid: '',
|
||||
audit_status: '',
|
||||
audit_status: undefined,
|
||||
created_at: [],
|
||||
sort_column: undefined,
|
||||
sort_order: undefined,
|
||||
@ -11,13 +11,13 @@ export const INITIAL_QUERY = {
|
||||
export enum EnumCheckStatus {
|
||||
All = '',
|
||||
Wait = 1,
|
||||
Checking = 2,
|
||||
Checking = 2,
|
||||
Passed = 3,
|
||||
}
|
||||
export enum EnumManuscriptType {
|
||||
All = '',
|
||||
Image = 0,
|
||||
Video = 1,
|
||||
Video = 1,
|
||||
}
|
||||
|
||||
export const CHECK_STATUS = [
|
||||
@ -25,19 +25,19 @@ export const CHECK_STATUS = [
|
||||
name: '待审核',
|
||||
id: EnumCheckStatus.Wait,
|
||||
backgroundColor: '#F2F3F5',
|
||||
color: '#3C4043'
|
||||
color: '#3C4043',
|
||||
},
|
||||
{
|
||||
name: '审核中',
|
||||
id: EnumCheckStatus.Checking,
|
||||
backgroundColor: '#FFF7E5',
|
||||
color: '#FFAE00'
|
||||
color: '#FFAE00',
|
||||
},
|
||||
{
|
||||
name: '已通过',
|
||||
id: EnumCheckStatus.Passed,
|
||||
backgroundColor: '#EBF7F2',
|
||||
color: '#25C883'
|
||||
color: '#25C883',
|
||||
},
|
||||
];
|
||||
export const MANUSCRIPT_TYPE = [
|
||||
@ -53,4 +53,4 @@ export const MANUSCRIPT_TYPE = [
|
||||
label: '视频',
|
||||
value: EnumManuscriptType.Video,
|
||||
},
|
||||
]
|
||||
];
|
||||
|
||||
@ -8,16 +8,15 @@
|
||||
>
|
||||
<ManuscriptTable :dataSource="dataSource" @sorterChange="handleSorterChange" @delete="handleDelete" />
|
||||
<div v-if="pageInfo.total > 0" class="pagination-row">
|
||||
<a-pagination
|
||||
<Pagination
|
||||
:total="pageInfo.total"
|
||||
size="mini"
|
||||
show-total
|
||||
show-jumper
|
||||
show-page-size
|
||||
size="small"
|
||||
:showTotal="(total, range) => `共 ${total} 条`"
|
||||
showSizeChanger
|
||||
showQuickJumper
|
||||
:current="pageInfo.page"
|
||||
:page-size="pageInfo.page_size"
|
||||
:pageSize="pageInfo.page_size"
|
||||
@change="onPageChange"
|
||||
@page-size-change="onPageSizeChange"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
@ -27,7 +26,7 @@
|
||||
</template>
|
||||
<script lang="jsx" setup>
|
||||
import { defineComponent } from 'vue';
|
||||
import { Button } from '@arco-design/web-vue';
|
||||
import { Button, Pagination } from 'ant-design-vue';
|
||||
import FilterBlock from './components/filter-block';
|
||||
import ManuscriptTable from './components/manuscript-table';
|
||||
import DeleteManuscriptModal from './components/manuscript-table/delete-manuscript-modal.vue';
|
||||
@ -36,13 +35,10 @@ import { useTableSelectionWithPagination } from '@/hooks/useTableSelectionWithPa
|
||||
import { getWorksPage } from '@/api/all/generationWorkshop.ts';
|
||||
import { INITIAL_QUERY, EnumCheckStatus } from '@/views/material-center/components/finished-products/manuscript/list/constants.ts';
|
||||
|
||||
const { dataSource, pageInfo, onPageChange, onPageSizeChange, resetPageInfo } = useTableSelectionWithPagination({
|
||||
const { dataSource, pageInfo, onPageChange, resetPageInfo } = useTableSelectionWithPagination({
|
||||
onPageChange: () => {
|
||||
getData();
|
||||
},
|
||||
onPageSizeChange: () => {
|
||||
getData();
|
||||
},
|
||||
});
|
||||
const query = ref(cloneDeep(INITIAL_QUERY));
|
||||
const addManuscriptModalRef = ref(null);
|
||||
|
||||
@ -1,18 +1,19 @@
|
||||
<template>
|
||||
<a-modal v-model:visible="visible" title="确认提示" width="480px" @close="onClose">
|
||||
<Modal v-model:open="visible" centered title="确认提示" width="480px" @cancel="onClose">
|
||||
<div class="flex items-center">
|
||||
<img :src="icon1" width="20" height="20" class="mr-12px" />
|
||||
<span>确认取消上传这 {{ num }} 个文件吗?此操作不可恢复。</span>
|
||||
</div>
|
||||
<template #footer>
|
||||
<a-button size="medium" @click="onClose">继续编辑</a-button>
|
||||
<a-button type="primary" class="ml-8px" size="medium" @click="onConfirm">确认取消</a-button>
|
||||
<Button size="medium" @click="onClose">继续编辑</Button>
|
||||
<Button type="primary" class="ml-8px" size="medium" @click="onConfirm">确认取消</Button>
|
||||
</template>
|
||||
</a-modal>
|
||||
</Modal>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref } from 'vue';
|
||||
import { Button, Modal } from 'ant-design-vue';
|
||||
import icon1 from '@/assets/img/media-account/icon-warn-1.png';
|
||||
|
||||
const router = useRouter();
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
<script lang="jsx">
|
||||
import { Button, Message as AMessage } from '@arco-design/web-vue';
|
||||
import { Button, message } from 'ant-design-vue';
|
||||
import TextOverTips from '@/components/text-over-tips';
|
||||
import EditForm, { ENUM_UPLOAD_STATUS, INITIAL_VIDEO_INFO } from '../components/edit-form';
|
||||
import CancelUploadModal from './cancel-upload-modal.vue';
|
||||
@ -45,7 +45,7 @@ export default {
|
||||
(item) => item.videoInfo?.uploadStatus === ENUM_UPLOAD_STATUS.UPLOADING,
|
||||
);
|
||||
if (uploadingVideos.length > 0) {
|
||||
AMessage.warning(`有 ${uploadingVideos.length} 个视频正在上传中,请等待上传完成后再提交`);
|
||||
message.warning(`有 ${uploadingVideos.length} 个视频正在上传中,请等待上传完成后再提交`);
|
||||
return;
|
||||
}
|
||||
|
||||
@ -59,7 +59,7 @@ export default {
|
||||
}
|
||||
|
||||
if (errorDataCards.value.length > 0) {
|
||||
AMessage.warning(`有 ${errorDataCards.value.length} 个必填信息未填写,请检查`);
|
||||
message.warning(`有 ${errorDataCards.value.length} 个必填信息未填写,请检查`);
|
||||
|
||||
setTimeout(() => {
|
||||
const el = document.getElementById(`card-${errorDataCards.value[0]?.id}`);
|
||||
@ -79,7 +79,7 @@ export default {
|
||||
if (action === 'batchUpload') {
|
||||
uploadSuccessModal.value?.open(data);
|
||||
} else {
|
||||
AMessage.success('上传成功');
|
||||
message.success('上传成功');
|
||||
if (action === 'uploadAndCheck') {
|
||||
slsWithCatch('manuscriptCheckIds', data);
|
||||
router.push({ name: 'ManuscriptCheck' });
|
||||
@ -145,10 +145,10 @@ export default {
|
||||
if (works.value.length > 1) {
|
||||
return (
|
||||
<>
|
||||
<Button size="medium" type="outline" onClick={onCancel} class="mr-12px">
|
||||
<Button type="primary" ghost onClick={onCancel} class="mr-12px">
|
||||
取消上传
|
||||
</Button>
|
||||
<Button type="primary" size="medium" onClick={() => onUpload('batchUpload')} loading={uploadLoading.value}>
|
||||
<Button type="primary" onClick={() => onUpload('batchUpload')} loading={uploadLoading.value}>
|
||||
{uploadLoading.value ? '批量上传中...' : '批量上传'}
|
||||
</Button>
|
||||
</>
|
||||
@ -156,12 +156,13 @@ export default {
|
||||
} else {
|
||||
return (
|
||||
<>
|
||||
<Button size="medium" type="outline" onClick={onCancel} class="mr-12px">
|
||||
<Button type="primary" ghost onClick={onCancel} class="mr-12px">
|
||||
取消上传
|
||||
</Button>
|
||||
<Button
|
||||
size="medium"
|
||||
type="outline"
|
||||
type="primary"
|
||||
ghost
|
||||
onClick={() => onUpload('singleUpload')}
|
||||
class="mr-12px"
|
||||
loading={uploadLoading.value}
|
||||
@ -311,7 +312,7 @@ export default {
|
||||
>
|
||||
{renderFooterRow()}
|
||||
</footer>
|
||||
|
||||
|
||||
<CancelUploadModal ref={cancelUploadModal} />
|
||||
<UploadSuccessModal ref={uploadSuccessModal} />
|
||||
</>
|
||||
|
||||
@ -1,5 +1,12 @@
|
||||
<template>
|
||||
<a-modal v-model:visible="visible" title="提示" width="480px" @close="onClose" modal-class="upload-success11-modal">
|
||||
<Modal
|
||||
v-model:open="visible"
|
||||
title="提示"
|
||||
centered
|
||||
width="480px"
|
||||
@cancel="onClose"
|
||||
wrapClassName="upload-success11-modal"
|
||||
>
|
||||
<div class="flex items-center flex-col justify-center">
|
||||
<img :src="icon1" width="80" height="80" class="mb-16px" />
|
||||
<span class="text-18px lh-26px font-400 color-#211F24 md">上传成功</span>
|
||||
@ -7,14 +14,15 @@
|
||||
<p class="text-14px lh-22px font-400 color-#737478 ld">检测是否存在违规内容</p>
|
||||
</div>
|
||||
<template #footer>
|
||||
<a-button size="medium" @click="onBack">回到列表</a-button>
|
||||
<a-button type="primary" class="ml-8px" size="medium" @click="onConfirm">批量审核</a-button>
|
||||
<Button size="medium" @click="onBack">回到列表</Button>
|
||||
<Button type="primary" class="ml-8px" size="medium" @click="onConfirm">批量审核</Button>
|
||||
</template>
|
||||
</a-modal>
|
||||
</Modal>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref } from 'vue';
|
||||
import { Button, Modal } from 'ant-design-vue';
|
||||
import { slsWithCatch } from '@/utils/stroage.ts';
|
||||
import icon1 from '@/assets/img/media-account/icon-feedback-success.png';
|
||||
|
||||
|
||||
@ -3,51 +3,30 @@
|
||||
<div class="filter-row">
|
||||
<div class="filter-row-item">
|
||||
<span class="label">文件名称</span>
|
||||
<a-input
|
||||
v-model="query.name"
|
||||
<Input
|
||||
v-model:value="query.name"
|
||||
class="!w-240px"
|
||||
placeholder="请输入文件名称"
|
||||
size="medium"
|
||||
allow-clear
|
||||
allowClear
|
||||
@change="handleSearch"
|
||||
>
|
||||
<template #prefix>
|
||||
<icon-search />
|
||||
</template>
|
||||
</a-input>
|
||||
</Input>
|
||||
</div>
|
||||
<div class="filter-row-item">
|
||||
<span class="label">序号</span>
|
||||
<a-space size="medium">
|
||||
<a-input
|
||||
v-model="query.uid"
|
||||
class="!w-160px"
|
||||
placeholder="请输入序号"
|
||||
size="medium"
|
||||
allow-clear
|
||||
@change="handleSearch"
|
||||
>
|
||||
<template #prefix>
|
||||
<icon-search />
|
||||
</template>
|
||||
</a-input>
|
||||
</a-space>
|
||||
<Input v-model:value="query.uid" class="!w-160px" placeholder="请输入序号" allowClear @change="handleSearch">
|
||||
<template #prefix>
|
||||
<icon-search />
|
||||
</template>
|
||||
</Input>
|
||||
</div>
|
||||
<!-- <div class="filter-row-item">
|
||||
<span class="label">来源</span>
|
||||
<CommonSelect
|
||||
placeholder="请选择所属项目"
|
||||
:options="CHECK_STATUS"
|
||||
v-model="query.audit_status"
|
||||
class="!w-160px"
|
||||
:multiple="false"
|
||||
@change="handleSearch"
|
||||
/>
|
||||
</div> -->
|
||||
<div class="filter-row-item">
|
||||
<span class="label">上传时间</span>
|
||||
<a-range-picker
|
||||
v-model="created_at"
|
||||
<DatePicker.RangePicker
|
||||
v-model:value="created_at"
|
||||
size="medium"
|
||||
allow-clear
|
||||
format="YYYY-MM-DD"
|
||||
@ -56,26 +35,27 @@
|
||||
/>
|
||||
</div>
|
||||
<div class="filter-row-item">
|
||||
<a-button type="outline" class="mr-12px" size="medium" @click="handleSearch">
|
||||
<Button type="primary" ghost class="mr-12px" size="medium" @click="handleSearch">
|
||||
<template #icon>
|
||||
<icon-search />
|
||||
<icon-search class="mr-8px" />
|
||||
</template>
|
||||
<template #default>搜索</template>
|
||||
</a-button>
|
||||
<a-button size="medium" @click="handleReset">
|
||||
</Button>
|
||||
<Button size="medium" @click="handleReset">
|
||||
<template #icon>
|
||||
<icon-refresh />
|
||||
<icon-refresh class="mr-8px" />
|
||||
</template>
|
||||
<template #default>重置</template>
|
||||
</a-button>
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { defineEmits, defineProps } from 'vue';
|
||||
// import CommonSelect from '@/components/common-select';
|
||||
import { defineEmits, defineProps, ref, nextTick } from 'vue';
|
||||
import { Button, Input, DatePicker } from 'ant-design-vue';
|
||||
import dayjs from 'dayjs';
|
||||
|
||||
const props = defineProps({
|
||||
query: {
|
||||
@ -84,7 +64,7 @@ const props = defineProps({
|
||||
},
|
||||
});
|
||||
|
||||
const emits = defineEmits('search', 'reset', 'update:query');
|
||||
const emits = defineEmits(['search', 'reset', 'update:query']);
|
||||
|
||||
const created_at = ref([]);
|
||||
|
||||
@ -112,10 +92,8 @@ const onDateChange = (value) => {
|
||||
handleSearch();
|
||||
};
|
||||
|
||||
|
||||
const handleReset = () => {
|
||||
created_at.value = [];
|
||||
emits('reset');
|
||||
};
|
||||
|
||||
</script>
|
||||
|
||||
@ -1,18 +1,19 @@
|
||||
<template>
|
||||
<a-modal v-model:visible="visible" title="删除文件" width="480px" @close="onClose">
|
||||
<Modal v-model:open="visible" title="删除文件" centered width="480px" @cancel="onClose">
|
||||
<div class="flex items-center">
|
||||
<img :src="icon1" width="20" height="20" class="mr-12px" />
|
||||
<span>确认删除 {{ fileName }} 文件吗?</span>
|
||||
</div>
|
||||
<template #footer>
|
||||
<a-button size="medium" @click="onClose">取消</a-button>
|
||||
<a-button type="primary" class="ml-16px" status="danger" size="medium" @click="onDelete">确认删除</a-button>
|
||||
<Button size="medium" @click="onClose">取消</Button>
|
||||
<Button type="primary" class="ml-16px" danger size="medium" @click="onDelete">确认删除</Button>
|
||||
</template>
|
||||
</a-modal>
|
||||
</Modal>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref } from 'vue';
|
||||
import { Button, Modal, message } from 'ant-design-vue';
|
||||
import { deleteRawMaterial, batchDeleteRawMaterials } from '@/api/all/generationWorkshop';
|
||||
import icon1 from '@/assets/img/media-account/icon-warn-1.png';
|
||||
|
||||
@ -43,7 +44,7 @@ async function onDelete() {
|
||||
const _params = isBatch.value ? { ids: fileId.value } : fileId.value;
|
||||
const { code } = await _fn(_params);
|
||||
if (code === 200) {
|
||||
AMessage.success('删除成功');
|
||||
message.success('删除成功');
|
||||
isBatch.value ? emits('batchUpdate') : emits('update');
|
||||
|
||||
onClose();
|
||||
|
||||
@ -1,101 +1,92 @@
|
||||
<template>
|
||||
<a-table
|
||||
<Table
|
||||
ref="tableRef"
|
||||
:data="dataSource"
|
||||
row-key="id"
|
||||
column-resizable
|
||||
:dataSource="dataSource"
|
||||
rowKey="id"
|
||||
:pagination="false"
|
||||
:scroll="{ x: '100%' }"
|
||||
class="flex-1 manuscript-table w-100%"
|
||||
bordered
|
||||
:row-selection="rowSelection"
|
||||
:selected-row-keys="selectedRowKeys"
|
||||
@sorter-change="handleSorterChange"
|
||||
@select="(selectedKeys, rowKeyValue, record) => emits('select', selectedKeys, rowKeyValue, record)"
|
||||
@select-all="(check) => emits('selectAll', check)"
|
||||
:rowSelection="rowSelection"
|
||||
:showSorterTooltip="false"
|
||||
@change="handleTableChange"
|
||||
>
|
||||
<template #empty>
|
||||
<template #emptyText>
|
||||
<NoData text="暂无文件" />
|
||||
</template>
|
||||
<template #columns>
|
||||
<a-table-column
|
||||
v-for="column in tableColumns"
|
||||
:key="column.dataIndex"
|
||||
:data-index="column.dataIndex"
|
||||
:fixed="column.fixed"
|
||||
:width="column.width"
|
||||
:min-width="column.minWidth"
|
||||
:sortable="column.sortable"
|
||||
:align="column.align"
|
||||
ellipsis
|
||||
tooltip
|
||||
>
|
||||
<template #title>
|
||||
<div class="flex items-center">
|
||||
<span class="cts mr-4px">{{ column.title }}</span>
|
||||
<a-tooltip v-if="column.tooltip" :content="column.tooltip" position="top">
|
||||
<icon-question-circle class="tooltip-icon color-#737478" size="16" />
|
||||
</a-tooltip>
|
||||
<Column
|
||||
v-for="column in tableColumns"
|
||||
:key="column.dataIndex"
|
||||
:dataIndex="column.dataIndex"
|
||||
:fixed="column.fixed"
|
||||
:width="column.width"
|
||||
:minWidth="column.minWidth"
|
||||
:sorter="column.sortable"
|
||||
:align="column.align"
|
||||
:ellipsis="true"
|
||||
>
|
||||
<template #title>
|
||||
<span class="cts mr-4px">{{ column.title }}</span>
|
||||
<Tooltip v-if="column.tooltip" :title="column.tooltip" placement="top">
|
||||
<icon-question-circle class="tooltip-icon color-#737478" size="16" />
|
||||
</Tooltip>
|
||||
</template>
|
||||
<template v-if="column.dataIndex === 'name'" #customRender="{ record }">
|
||||
<div class="flex items-center">
|
||||
<HoverImagePreview :src="record.cover">
|
||||
<ImgLazyLoad :width="64" :height="64" :src="record.cover" class="!rounded-6px mr-16px" />
|
||||
</HoverImagePreview>
|
||||
<div class="flex-1 flex flex-col overflow-hidden">
|
||||
<TextOverTips :context="record.name" :line="1" class="cts mb-4px regular" />
|
||||
<TextOverTips :context="`序号:${record.uid}`" :line="1" class="cts !color-#737478 regular" />
|
||||
</div>
|
||||
</template>
|
||||
<template v-if="column.dataIndex === 'name'" #cell="{ record }">
|
||||
<div class="flex items-center">
|
||||
<HoverImagePreview :src="record.cover">
|
||||
<a-image :width="64" :height="64" :src="record.cover" class="!rounded-8px mr-16px" fit="cover">
|
||||
<template #error>
|
||||
<img :src="icon4" class="w-full h-full" />
|
||||
</template>
|
||||
</a-image>
|
||||
</HoverImagePreview>
|
||||
<div class="flex-1 flex flex-col overflow-hidden">
|
||||
<TextOverTips :context="record.name" :line="1" class="cts mb-4px regular" />
|
||||
<TextOverTips :context="`序号:${record.uid}`" :line="1" class="cts !color-#737478 regular" />
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<template v-else-if="column.dataIndex === 'type'" #cell="{ record }">
|
||||
{{ TABS_LIST.find((item) => item.value === record.type)?.label ?? '-' }}
|
||||
</template>
|
||||
<template v-else-if="column.dataIndex === 'size'" #cell="{ record }">
|
||||
<span class="cts num">{{ formatFileSize(record.size) }}</span>
|
||||
</template>
|
||||
<template v-else-if="column.dataIndex === 'origin'" #cell="{ record }">
|
||||
{{ ORIGIN_LIST.find((item) => item.value === record.origin)?.label ?? '-' }}
|
||||
</template>
|
||||
<template v-else-if="['uploader', 'last_modifier'].includes(column.dataIndex)" #cell="{ record }">
|
||||
{{ record[column.dataIndex].name || record[column.dataIndex].mobile }}
|
||||
</template>
|
||||
<template #cell="{ record }" v-else-if="['created_at'].includes(column.dataIndex)">
|
||||
<span class="cts num">{{ exactFormatTime(record[column.dataIndex]) }}</span>
|
||||
</template>
|
||||
<template v-else-if="column.dataIndex === 'operation'" #cell="{ record }">
|
||||
<div class="flex items-center">
|
||||
<img class="mr-8px cursor-pointer" :src="icon1" width="14" height="14" @click="onDelete(record)" />
|
||||
<a-button type="outline" size="mini" @click="onDownload(record)">下载</a-button>
|
||||
</div>
|
||||
</template>
|
||||
<template v-else #cell="{ record }">
|
||||
{{ formatTableField(column, record, true) }}
|
||||
</template>
|
||||
</a-table-column>
|
||||
</template>
|
||||
</a-table>
|
||||
</div>
|
||||
</template>
|
||||
<template v-else-if="column.dataIndex === 'type'" #customRender="{ record }">
|
||||
{{ TABS_LIST.find((item) => item.value === record.type)?.label ?? '-' }}
|
||||
</template>
|
||||
<template v-else-if="column.dataIndex === 'size'" #customRender="{ record }">
|
||||
<span class="cts num">{{ formatFileSize(record.size) }}</span>
|
||||
</template>
|
||||
<template v-else-if="column.dataIndex === 'origin'" #customRender="{ record }">
|
||||
{{ ORIGIN_LIST.find((item) => item.value === record.origin)?.label ?? '-' }}
|
||||
</template>
|
||||
<template v-else-if="['uploader', 'last_modifier'].includes(column.dataIndex)" #customRender="{ record }">
|
||||
{{ record[column.dataIndex].name || record[column.dataIndex].mobile }}
|
||||
</template>
|
||||
<template #customRender="{ record }" v-else-if="['created_at'].includes(column.dataIndex)">
|
||||
<span class="cts num">{{ exactFormatTime(record[column.dataIndex]) }}</span>
|
||||
</template>
|
||||
<template v-else-if="column.dataIndex === 'operation'" #customRender="{ record }">
|
||||
<div class="flex items-center">
|
||||
<img class="mr-8px cursor-pointer" :src="icon1" width="14" height="14" @click="onDelete(record)" />
|
||||
<Button type="primary" ghost size="small" @click="onDownload(record)">下载</Button>
|
||||
</div>
|
||||
</template>
|
||||
<template v-else #customRender="{ record }">
|
||||
{{ formatTableField(column, record, true) }}
|
||||
</template>
|
||||
</Column>
|
||||
</Table>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref } from 'vue';
|
||||
import { ref, computed } from 'vue';
|
||||
import { Button, Tooltip, Table, Image } from 'ant-design-vue';
|
||||
const { Column } = Table;
|
||||
import { formatTableField, exactFormatTime, formatFileSize, downloadByUrl } from '@/utils/tools';
|
||||
import { slsWithCatch } from '@/utils/stroage.ts';
|
||||
import { TABS_LIST, ORIGIN_LIST } from '../../constants';
|
||||
|
||||
import TextOverTips from '@/components/text-over-tips';
|
||||
import ShareModal from '@/views/material-center/components/finished-products/manuscript/components/share-manuscript-modal/share-modal.vue';
|
||||
// import ShareModal from '@/views/material-center/components/finished-products/manuscript/components/share-manuscript-modal/share-modal.vue';
|
||||
import HoverImagePreview from '@/components/hover-image-preview';
|
||||
import ImgLazyLoad from '@/components/img-lazy-load';
|
||||
|
||||
import icon1 from '@/assets/img/media-account/icon-delete.png';
|
||||
import icon2 from '@/assets/img/creative-generation-workshop/icon-photo.png';
|
||||
import icon3 from '@/assets/img/creative-generation-workshop/icon-video.png';
|
||||
import icon4 from '@/assets/img/error-img.png';
|
||||
// import icon2 from '@/assets/img/creative-generation-workshop/icon-photo.png';
|
||||
// import icon3 from '@/assets/img/creative-generation-workshop/icon-video.png';
|
||||
// import icon4 from '@/assets/img/error-img.png';
|
||||
|
||||
const emits = defineEmits(['sorterChange', 'delete', 'select', 'selectAll']);
|
||||
const router = useRouter();
|
||||
@ -109,10 +100,6 @@ const props = defineProps({
|
||||
type: Array,
|
||||
default: () => [],
|
||||
},
|
||||
rowSelection: {
|
||||
type: Object,
|
||||
default: () => {},
|
||||
},
|
||||
selectedRowKeys: {
|
||||
type: Array,
|
||||
default: () => [],
|
||||
@ -121,8 +108,20 @@ const props = defineProps({
|
||||
|
||||
const tableRef = ref(null);
|
||||
|
||||
const handleSorterChange = (column, order) => {
|
||||
emits('sorterChange', column, order === 'ascend' ? 'asc' : 'desc');
|
||||
const handleTableChange = (pagination, filters, sorter) => {
|
||||
if (sorter && sorter.field) {
|
||||
emits('sorterChange', sorter.field, sorter.order === 'ascend' ? 'asc' : 'desc');
|
||||
}
|
||||
};
|
||||
|
||||
const rowSelection = {
|
||||
selectedRowKeys: computed(() => props.selectedRowKeys),
|
||||
onSelect: (record, selected) => {
|
||||
emits('select', record, selected);
|
||||
},
|
||||
onSelectAll: (selected) => {
|
||||
emits('selectAll', selected);
|
||||
},
|
||||
};
|
||||
const onDelete = (item) => {
|
||||
emits('delete', item);
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
<script lang="tsx">
|
||||
import { provide } from 'vue';
|
||||
import { Tabs, TabPane } from 'ant-design-vue';
|
||||
import { Tabs, TabPane, Button, Pagination } from 'ant-design-vue';
|
||||
import { TABS_LIST, RawMaterialType, INITIAL_QUERY, TABLE_COLUMNS } from './constants';
|
||||
import FilterBlock from './components/filter-block/index.vue';
|
||||
import RawMaterialTable from './components/table/index.vue';
|
||||
@ -14,9 +14,7 @@ export default defineComponent({
|
||||
const {
|
||||
dataSource,
|
||||
pageInfo,
|
||||
rowSelection,
|
||||
onPageChange,
|
||||
onPageSizeChange,
|
||||
selectedRowKeys,
|
||||
selectedRows,
|
||||
handleSelect,
|
||||
@ -26,9 +24,6 @@ export default defineComponent({
|
||||
onPageChange: () => {
|
||||
getData();
|
||||
},
|
||||
onPageSizeChange: () => {
|
||||
getData();
|
||||
},
|
||||
});
|
||||
|
||||
const deleteRawMaterialModalRef = ref(null);
|
||||
@ -106,14 +101,20 @@ export default defineComponent({
|
||||
</div>
|
||||
<div class="table-wrap bg-#fff rounded-8px px-24px py-24px flex flex-col">
|
||||
<div class="flex justify-end mb-12px">
|
||||
<a-button type="outline" class="w-fit" size="medium" onClick={handleBatchDelete}>
|
||||
<Button
|
||||
type="primary"
|
||||
ghost
|
||||
class="w-fit"
|
||||
size="medium"
|
||||
onClick={handleBatchDelete}
|
||||
disabled={!selectedRows.value.length}
|
||||
>
|
||||
批量删除
|
||||
</a-button>
|
||||
</Button>
|
||||
</div>
|
||||
|
||||
<RawMaterialTable
|
||||
tableColumns={TABLE_COLUMNS}
|
||||
rowSelection={rowSelection}
|
||||
selectedRowKeys={selectedRowKeys.value}
|
||||
dataSource={dataSource.value}
|
||||
onSorterChange={handleSorterChange}
|
||||
@ -123,16 +124,15 @@ export default defineComponent({
|
||||
/>
|
||||
{pageInfo.value.total > 0 && (
|
||||
<div class="pagination-row">
|
||||
<a-pagination
|
||||
<Pagination
|
||||
total={pageInfo.value.total}
|
||||
size="mini"
|
||||
show-total
|
||||
show-jumper
|
||||
show-page-size
|
||||
size="small"
|
||||
showTotal={(total: number) => `共 ${total} 条记录`}
|
||||
showSizeChanger
|
||||
showQuickJumper
|
||||
current={pageInfo.value.page}
|
||||
pageSize={pageInfo.value.page_size}
|
||||
onChange={onPageChange}
|
||||
onPageSizeChange={onPageSizeChange}
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
|
||||
@ -1,10 +1,10 @@
|
||||
<template>
|
||||
<div class="brand-wrap">
|
||||
<div class="filter-wrap bg-#fff rounded-8px ">
|
||||
<div class="filter-wrap bg-#fff rounded-8px">
|
||||
<div class="top flex h-64px px-24px py-10px justify-between items-center">
|
||||
<p class="text-18px font-400 lh-26px color-#211F24 title">品牌物料</p>
|
||||
<div class="flex items-center">
|
||||
<a-button class="add-btn" type="primary" @click="handleAdd">+ 添加品牌</a-button>
|
||||
<Button type="primary" class="add-btn" @click="handleAdd">+ 添加品牌</Button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@ -12,32 +12,33 @@
|
||||
<div class="filter-row flex mb-20px">
|
||||
<div class="filter-row-item flex items-center">
|
||||
<span class="label">品牌名称</span>
|
||||
<a-space size="medium">
|
||||
<a-input v-model="query.name" class="w-240px" placeholder="请搜索..." size="medium" allow-clear>
|
||||
<Space size="medium">
|
||||
<Input v-model:value="query.name" class="w-240px" placeholder="请搜索..." size="medium" allowClear>
|
||||
<template #prefix>
|
||||
<icon-search />
|
||||
</template>
|
||||
</a-input>
|
||||
</a-space>
|
||||
</Input>
|
||||
</Space>
|
||||
</div>
|
||||
<div class="filter-row flex">
|
||||
<a-button type="outline" class="mr-12px" size="medium" @click="handleSearch">
|
||||
<Button type="outline" ghost class="mr-12px" @click="handleSearch">
|
||||
<template #icon>
|
||||
<icon-search />
|
||||
<icon-search class="mr-8px" />
|
||||
</template>
|
||||
<template #default>搜索</template>
|
||||
</a-button>
|
||||
<a-button size="medium" @click="handleReset">
|
||||
</Button>
|
||||
<Button @click="handleReset">
|
||||
<template #icon>
|
||||
<icon-refresh />
|
||||
<icon-refresh class="mr-8px" />
|
||||
</template>
|
||||
<template #default>重置</template>
|
||||
</a-button>
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
<a-modal
|
||||
v-model:visible="modalVisible"
|
||||
:mask-closable="false"
|
||||
<Modal
|
||||
v-model:open="modalVisible"
|
||||
:maskClosable="false"
|
||||
centered
|
||||
:esc-to-close="false"
|
||||
width="510px"
|
||||
@cancel="handleModalCancel"
|
||||
@ -45,78 +46,77 @@
|
||||
<template #title>
|
||||
<span class="modal-title">{{ form.id > 0 ? '编辑品牌' : '添加品牌' }}</span>
|
||||
</template>
|
||||
<a-form :model="form" :rules="formRule" ref="formRef" layout="horizontal" auto-label-width>
|
||||
<a-form-item field="name" label="品牌名称">
|
||||
<a-input v-model="form.name" class="h-36px" placeholder="请输入..." />
|
||||
</a-form-item>
|
||||
<a-form-item field="logo" class="form-item-logo" label="标准版Logo">
|
||||
<a-space>
|
||||
<Form
|
||||
:model="form"
|
||||
:rules="formRule"
|
||||
ref="formRef"
|
||||
layout="horizontal"
|
||||
labelAlign="right"
|
||||
:labelCol="{ span: 4 }"
|
||||
:wrapperCol="{ span: 20 }"
|
||||
>
|
||||
<FormItem name="name" label="品牌名称">
|
||||
<Input v-model:value="form.name" class="h-36px" placeholder="请输入..." />
|
||||
</FormItem>
|
||||
<FormItem name="logo" class="form-item-logo" label="标准版Logo">
|
||||
<div class="inline-flex">
|
||||
<ImageUpload v-model="form.logo" :limit="1"></ImageUpload>
|
||||
</a-space>
|
||||
<a-space>
|
||||
</div>
|
||||
<div class="inline-flex">
|
||||
<span class="form-tip">(品牌常规展示使用,支持PNG,JPG格式)</span>
|
||||
</a-space>
|
||||
</a-form-item>
|
||||
<a-form-item field="otherLogos" class="form-item-logo" label="其他Logo">
|
||||
</div>
|
||||
</FormItem>
|
||||
<FormItem name="otherLogos" class="form-item-logo" label="其他Logo">
|
||||
<ImageUpload v-model="form.other_logos" :limit="3"></ImageUpload>
|
||||
</a-form-item>
|
||||
<a-form-item field="slogan" label="Slogan">
|
||||
<a-textarea v-model="form.slogan" placeholder="请输入..." :max-length="50" show-word-limit />
|
||||
</a-form-item>
|
||||
</a-form>
|
||||
</FormItem>
|
||||
<FormItem name="slogan" label="Slogan">
|
||||
<TextArea v-model:value="form.slogan" placeholder="请输入..." :maxlength="50" showCount />
|
||||
</FormItem>
|
||||
</Form>
|
||||
<template #footer>
|
||||
<a-button @click="handleModalCancel">取消</a-button>
|
||||
<a-button type="primary" @click="handleModalOk">{{ btn_str }}</a-button>
|
||||
<Button @click="handleModalCancel">取消</Button>
|
||||
<Button type="primary" @click="handleModalOk">{{ btn_str }}</Button>
|
||||
</template>
|
||||
</a-modal>
|
||||
</Modal>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="table-wrap bg-#fff rounded-8px px-24px py-24px flex flex-col"
|
||||
>
|
||||
<a-table :data="tableData" ref="tableRef" :pagination="false">
|
||||
<template #columns>
|
||||
<a-table-column title="品牌名称" data-index="name" />
|
||||
<a-table-column title="品牌logo" data-index="logo">
|
||||
<template #cell="{ record }">
|
||||
<img :src="record.logo" style="width: 50px; height: 50px" />
|
||||
</template>
|
||||
</a-table-column>
|
||||
<a-table-column title="Slogan" data-index="slogan" />
|
||||
<a-table-column width="150" min-widht="150" title="操作" data-index="optional">
|
||||
<template #cell="{ record }">
|
||||
<a-space size="medium">
|
||||
<a-space>
|
||||
<a-popconfirm
|
||||
content="确定删除吗?"
|
||||
type="warning"
|
||||
ok-text="确认删除"
|
||||
cancel-text="取消"
|
||||
@ok="deleteBrand(record.id)"
|
||||
>
|
||||
<icon-delete></icon-delete>
|
||||
</a-popconfirm>
|
||||
</a-space>
|
||||
<a-space>
|
||||
<a-button class="edit-btn" type="outline" @click="handleEdit(record.id)">编辑</a-button>
|
||||
</a-space>
|
||||
</a-space>
|
||||
</template>
|
||||
</a-table-column>
|
||||
</template>
|
||||
</a-table>
|
||||
<div class="table-wrap bg-#fff rounded-8px px-24px py-24px flex flex-col">
|
||||
<Table :dataSource="tableData" ref="tableRef" :pagination="false" :showSorterTooltip="false">
|
||||
<Table.Column title="品牌名称" dataIndex="name" />
|
||||
<Table.Column title="品牌logo" dataIndex="logo">
|
||||
<template #customRender="{ record }">
|
||||
<img :src="record.logo" style="width: 50px; height: 50px" />
|
||||
</template>
|
||||
</Table.Column>
|
||||
<Table.Column title="Slogan" dataIndex="slogan" />
|
||||
<Table.Column :width="80" title="操作" dataIndex="optional">
|
||||
<template #customRender="{ record }">
|
||||
<Space>
|
||||
<Popconfirm
|
||||
title="确定删除吗?"
|
||||
okText="确认删除"
|
||||
cancelText="取消"
|
||||
@confirm="deleteBrand(record.id)"
|
||||
>
|
||||
<icon-delete></icon-delete>
|
||||
</Popconfirm>
|
||||
<Button type="outline" class="edit-btn" size="small" @click="handleEdit(record.id)">编辑</Button>
|
||||
</Space>
|
||||
</template>
|
||||
</Table.Column>
|
||||
</Table>
|
||||
|
||||
<div class="pagination-row">
|
||||
<a-pagination
|
||||
<Pagination
|
||||
:total="pageInfo.total"
|
||||
size="mini"
|
||||
show-total
|
||||
show-jumper
|
||||
show-page-size
|
||||
size="small"
|
||||
:showTotal="(total, range) => `共 ${total} 条`"
|
||||
showSizeChanger
|
||||
showQuickJumper
|
||||
:current="pageInfo.page"
|
||||
:page-size="pageInfo.pageSize"
|
||||
:pageSize="pageInfo.pageSize"
|
||||
@change="onPageChange"
|
||||
@page-size-change="onPageSizeChange"
|
||||
:hideOnSinglePage="false"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
@ -125,8 +125,9 @@
|
||||
|
||||
<script setup>
|
||||
import { ref, computed, reactive, onMounted } from 'vue';
|
||||
import { Message } from '@arco-design/web-vue';
|
||||
import { IconDelete } from '@arco-design/web-vue/es/icon';
|
||||
import { Button, Modal, Space, Form, FormItem, Pagination, Input, Table, message, Popconfirm } from 'ant-design-vue';
|
||||
const { TextArea } = Input;
|
||||
|
||||
import {
|
||||
addMaterials,
|
||||
@ -196,19 +197,16 @@ const handleReset = () => {
|
||||
reload();
|
||||
};
|
||||
|
||||
const onPageChange = (current) => {
|
||||
const onPageChange = (current, pageSize) => {
|
||||
pageInfo.page = current;
|
||||
pageInfo.pageSize = pageSize;
|
||||
handleSearch();
|
||||
};
|
||||
|
||||
const onPageSizeChange = (pageSize) => {
|
||||
pageInfo.pageSize = pageSize;
|
||||
reload();
|
||||
};
|
||||
const deleteBrand = (id) => {
|
||||
console.log(id, 'id');
|
||||
deleteMaterials(id).then(() => {
|
||||
Message.success('删除成功');
|
||||
message.success('删除成功');
|
||||
handleSearch();
|
||||
});
|
||||
};
|
||||
@ -231,24 +229,22 @@ function handleModalOk() {
|
||||
formRef.value
|
||||
.validate()
|
||||
.then((valid) => {
|
||||
if (!valid) {
|
||||
if (form.id) {
|
||||
updateMaterials(form.id, form).then(() => {
|
||||
Message.success('修改成功');
|
||||
handleSearch();
|
||||
});
|
||||
} else {
|
||||
addMaterials(form).then((response) => {
|
||||
Message.success('新增成功');
|
||||
handleSearch();
|
||||
});
|
||||
}
|
||||
modalVisible.value = false;
|
||||
if (form.id) {
|
||||
updateMaterials(form.id, form).then(() => {
|
||||
message.success('修改成功');
|
||||
handleSearch();
|
||||
});
|
||||
} else {
|
||||
addMaterials(form).then((response) => {
|
||||
message.success('新增成功');
|
||||
handleSearch();
|
||||
});
|
||||
}
|
||||
modalVisible.value = false;
|
||||
})
|
||||
.catch((error) => {
|
||||
console.error('验证失败:', error);
|
||||
Message.error('请检查表单填写是否正确');
|
||||
message.error('请检查表单填写是否正确');
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@ -37,6 +37,9 @@
|
||||
|
||||
|
||||
}
|
||||
:deep(.ant-popconfirm-buttons) {
|
||||
display: flex;
|
||||
}
|
||||
|
||||
:deep(.arco-input-wrapper),
|
||||
:deep(.arco-select-view-single),
|
||||
|
||||
@ -1,11 +1,11 @@
|
||||
.arco-modal {
|
||||
.arco-modal-body {
|
||||
.arco-form-item {
|
||||
.ant-modal {
|
||||
.ant-modal-body {
|
||||
.ant-form-item {
|
||||
margin-bottom: 16px;
|
||||
&:last-child {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
.arco-form-item-label {
|
||||
.ant-form-item-label {
|
||||
color: var(--Text-1, #211f24);
|
||||
font-family: $font-family-regular;
|
||||
font-size: 14px;
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
<template>
|
||||
<div class="business-wrap">
|
||||
<div class="filter-wrap bg-#fff rounded-8px border-1px border-#D7D7D9 border-solid">
|
||||
<div class="filter-wrap bg-#fff rounded-8px">
|
||||
<div class="top flex h-64px px-24px py-10px justify-between items-center">
|
||||
<p class="text-18px font-400 lh-26px color-#211F24 title">业务洞察报告</p>
|
||||
</div>
|
||||
@ -9,54 +9,59 @@
|
||||
<div class="filter-row flex mb-20px">
|
||||
<div class="filter-row-item flex items-center">
|
||||
<span class="label">服务/产品</span>
|
||||
<a-space size="medium">
|
||||
<a-input v-model="query.name" class="w-240px" placeholder="请搜索..." size="medium" allow-clear>
|
||||
<template #prefix>
|
||||
<icon-search />
|
||||
</template>
|
||||
</a-input>
|
||||
</a-space>
|
||||
<Input v-model:value="query.name" class="w-240px" placeholder="请搜索..." size="middle" allowClear>
|
||||
<template #prefix>
|
||||
<icon-search />
|
||||
</template>
|
||||
</Input>
|
||||
</div>
|
||||
<div class="filter-row-item flex items-center">
|
||||
<span class="label">时间筛选</span>
|
||||
<a-space class="w-240px">
|
||||
<a-range-picker size="medium" allow-clear format="YYYY-MM-DD HH:mm" class="w-100%" />
|
||||
</a-space>
|
||||
<Space class="w-240px">
|
||||
<DatePicker.RangePicker allowClear format="YYYY-MM-DD HH:mm" class="w-100%" />
|
||||
</Space>
|
||||
</div>
|
||||
|
||||
<div class="filter-row flex">
|
||||
<a-button type="outline" class="mr-12px" size="medium">
|
||||
<Button class="mr-12px outline-btn">
|
||||
<template #icon>
|
||||
<icon-search />
|
||||
</template>
|
||||
<template #default>搜索</template>
|
||||
</a-button>
|
||||
<a-button size="medium">
|
||||
搜索
|
||||
</Button>
|
||||
<Button>
|
||||
<template #icon>
|
||||
<icon-refresh />
|
||||
</template>
|
||||
<template #default>重置</template>
|
||||
</a-button>
|
||||
重置
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="table-wrap bg-#fff rounded-8px border-1px border-#D7D7D9 border-solid px-24px py-24px flex-1 flex flex-col"
|
||||
class="table-wrap bg-#fff rounded-8px px-24px py-24px flex-1 flex flex-col"
|
||||
>
|
||||
<a-table :columns="columns" :data="tableData" @change="handleChange" :pagination="false">
|
||||
</a-table>
|
||||
<Table :dataSource="tableData" :pagination="false" :showSorterTooltip="false" @change="handleChange">
|
||||
<Table.Column
|
||||
v-for="column in columns"
|
||||
:key="column.dataIndex"
|
||||
:title="column.title"
|
||||
:dataIndex="column.dataIndex"
|
||||
:width="column.width"
|
||||
:minWidth="column.minWidth"
|
||||
/>
|
||||
</Table>
|
||||
<div class="pagination-row">
|
||||
<a-pagination
|
||||
<Pagination
|
||||
:total="pageInfo.total"
|
||||
size="mini"
|
||||
show-total
|
||||
show-jumper
|
||||
show-page-size
|
||||
size="small"
|
||||
:showTotal="(total, range) => `共 ${total} 条`"
|
||||
showSizeChanger
|
||||
showQuickJumper
|
||||
:current="pageInfo.page"
|
||||
:page-size="pageInfo.pageSize"
|
||||
:pageSize="pageInfo.pageSize"
|
||||
@change="onPageChange"
|
||||
@page-size-change="onPageSizeChange"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
@ -65,6 +70,7 @@
|
||||
|
||||
<script setup lang="ts">
|
||||
import { reactive, ref } from 'vue';
|
||||
import { Button, Input, Space, Table, Pagination, DatePicker } from 'ant-design-vue';
|
||||
|
||||
const pageInfo = reactive({
|
||||
page: 1,
|
||||
@ -79,17 +85,19 @@ const listResult = reactive({
|
||||
data: [],
|
||||
total: 0,
|
||||
});
|
||||
const onPageSizeChange = () => {};
|
||||
const tableData = ref([]);
|
||||
const handleChange = () => {};
|
||||
const onPageChange = () => {};
|
||||
const columns = [
|
||||
const onPageChange = (page: number, pageSize:number) => {
|
||||
pageInfo.page = page;
|
||||
pageInfo.pageSize = pageSize;
|
||||
};
|
||||
const columns = [
|
||||
{
|
||||
title: '服务/产品',
|
||||
dataIndex: 'service_name',
|
||||
slotName: 'rank',
|
||||
width: 60,
|
||||
minWidth: 60,
|
||||
width: 100,
|
||||
minWidth: 100,
|
||||
},
|
||||
{
|
||||
title: '生成日期',
|
||||
@ -140,10 +148,12 @@ const columns = [
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
|
||||
:deep(.search-btn) {
|
||||
border-radius: 4px;
|
||||
border: 1px solid var(--Brand-Brand-6, #6d4cfe);
|
||||
color: #6d4cfe;
|
||||
:deep(.outline-btn) {
|
||||
border: 1px solid #d9d9d9;
|
||||
&:hover {
|
||||
color: #6d4cfe;
|
||||
border-color: #6d4cfe;
|
||||
}
|
||||
}
|
||||
|
||||
:deep(.edit-btn) {
|
||||
@ -157,9 +167,9 @@ const columns = [
|
||||
background: var(--BG-white, #fff);
|
||||
}
|
||||
|
||||
:deep(.arco-input-wrapper),
|
||||
:deep(.arcoInput-wrapper),
|
||||
:deep(.arco-select-view-single),
|
||||
:deep(.arco-textarea-wrapper),
|
||||
:deep(.ant-input),
|
||||
:deep(.arco-picker),
|
||||
:deep(.arco-select-view-multiple) {
|
||||
border-radius: 4px;
|
||||
@ -167,7 +177,7 @@ const columns = [
|
||||
background-color: #fff;
|
||||
|
||||
&:focus-within,
|
||||
&.arco-input-focus {
|
||||
&.arcoInput-focus {
|
||||
background-color: var(--color-bg-2);
|
||||
border-color: rgb(var(--primary-6));
|
||||
box-shadow: 0 0 0 0 var(--color-primary-light-2);
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
<template>
|
||||
<div class="competitive-wrap">
|
||||
<div class="filter-wrap bg-#fff rounded-8px border-1px border-#D7D7D9 border-solid">
|
||||
<div class="filter-wrap bg-#fff rounded-8px ">
|
||||
<div class="top flex h-64px px-24px py-10px justify-between items-center">
|
||||
<p class="text-18px font-400 lh-26px color-#211F24 title">竞品对比报告</p>
|
||||
</div>
|
||||
@ -9,54 +9,89 @@
|
||||
<div class="filter-row flex mb-20px">
|
||||
<div class="filter-row-item flex items-center">
|
||||
<span class="label">服务/产品</span>
|
||||
<a-space size="medium">
|
||||
<a-input v-model="query.name" class="w-240px" placeholder="请搜索..." size="medium" allow-clear>
|
||||
<Space>
|
||||
<Input v-model:value="query.name" class="w-240px" placeholder="请搜索..." allowClear>
|
||||
<template #prefix>
|
||||
<icon-search />
|
||||
</template>
|
||||
</a-input>
|
||||
</a-space>
|
||||
</Input>
|
||||
</Space>
|
||||
</div>
|
||||
<div class="filter-row-item flex items-center">
|
||||
<span class="label">时间筛选</span>
|
||||
<a-space class="w-240px">
|
||||
<a-range-picker size="medium" allow-clear format="YYYY-MM-DD HH:mm" class="w-100%" />
|
||||
</a-space>
|
||||
<Space class="w-240px">
|
||||
<DatePicker.RangePicker allow-clear format="YYYY-MM-DD HH:mm" class="w-100%" />
|
||||
</Space>
|
||||
</div>
|
||||
|
||||
<div class="filter-row flex">
|
||||
<a-button type="outline" class="mr-12px" size="medium">
|
||||
<Button type="primary" ghost class="mr-12px">
|
||||
<template #icon>
|
||||
<icon-search />
|
||||
<icon-search class="mr-8px" />
|
||||
</template>
|
||||
<template #default>搜索</template>
|
||||
</a-button>
|
||||
<a-button size="medium">
|
||||
</Button>
|
||||
<Button>
|
||||
<template #icon>
|
||||
<icon-refresh />
|
||||
<icon-refresh class="mr-8px" />
|
||||
</template>
|
||||
<template #default>重置</template>
|
||||
</a-button>
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="table-wrap bg-#fff rounded-8px border-1px border-#D7D7D9 border-solid px-24px py-24px flex-1 flex flex-col"
|
||||
class="table-wrap bg-#fff rounded-8px px-24px py-24px flex-1 flex flex-col"
|
||||
>
|
||||
<a-table :columns="columns" :data="tableData" @change="handleChange" :pagination="false">
|
||||
</a-table>
|
||||
<Table :dataSource="tableData" :pagination="false" :showSorterTooltip="false" @change="handleChange">
|
||||
<Table.Column
|
||||
title="服务/产品"
|
||||
dataIndex="service_name"
|
||||
:width="60"
|
||||
:minWidth="60"
|
||||
/>
|
||||
<Table.Column
|
||||
title="生成日期"
|
||||
dataIndex="create_time"
|
||||
:width="120"
|
||||
:minWidth="120"
|
||||
/>
|
||||
<Table.Column
|
||||
:width="180"
|
||||
:minWidth="180"
|
||||
title="竞争对手"
|
||||
dataIndex="customer"
|
||||
/>
|
||||
<Table.Column
|
||||
title="最后更新日期"
|
||||
dataIndex="volumeRate"
|
||||
:width="180"
|
||||
:minWidth="180"
|
||||
/>
|
||||
<Table.Column
|
||||
title="操作人"
|
||||
dataIndex="operator"
|
||||
:width="120"
|
||||
:minWidth="120"
|
||||
/>
|
||||
<Table.Column
|
||||
title="操作"
|
||||
dataIndex="operator"
|
||||
:width="120"
|
||||
:minWidth="120"
|
||||
/>
|
||||
</Table>
|
||||
<div class="pagination-row">
|
||||
<a-pagination
|
||||
<Pagination
|
||||
:total="pageInfo.total"
|
||||
size="mini"
|
||||
show-total
|
||||
show-jumper
|
||||
show-page-size
|
||||
size="small"
|
||||
:showTotal="(total, range) => `共 ${total} 条`"
|
||||
showSizeChanger
|
||||
showQuickJumper
|
||||
:current="pageInfo.page"
|
||||
:page-size="pageInfo.pageSize"
|
||||
:pageSize="pageInfo.pageSize"
|
||||
@change="onPageChange"
|
||||
@page-size-change="onPageSizeChange"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
@ -64,6 +99,7 @@
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { Button, Input, Space, Pagination, Table, DatePicker } from 'ant-design-vue';
|
||||
import { reactive, ref } from 'vue';
|
||||
|
||||
const pageInfo = reactive({
|
||||
@ -76,54 +112,14 @@ const query = reactive({
|
||||
});
|
||||
|
||||
const handleChange = () => {};
|
||||
const onPageChange = () => {};
|
||||
const onPageChange = (page: number, pageSize:number) => {
|
||||
pageInfo.page = page;
|
||||
pageInfo.pageSize = pageSize;
|
||||
};
|
||||
const onPageSizeChange = () => {};
|
||||
const tableData = ref([]);
|
||||
|
||||
const columns = [
|
||||
{
|
||||
title: '服务/产品',
|
||||
dataIndex: 'service_name',
|
||||
slotName: 'rank',
|
||||
width: 60,
|
||||
minWidth: 60,
|
||||
},
|
||||
{
|
||||
title: '生成日期',
|
||||
dataIndex: 'create_time',
|
||||
width: 120,
|
||||
minWidth: 120,
|
||||
},
|
||||
{
|
||||
titleSlotName: 'customer',
|
||||
width: 180,
|
||||
minWidth: 180,
|
||||
title: '竞争对手',
|
||||
dataIndex: 'customer',
|
||||
slotName: 'hot',
|
||||
},
|
||||
|
||||
{
|
||||
titleSlotName: 'lasterUpdateTime',
|
||||
title: '最后更新日期',
|
||||
dataIndex: 'volumeRate',
|
||||
width: 180,
|
||||
minWidth: 180,
|
||||
slotName: 'lasterUpdateTime',
|
||||
},
|
||||
{
|
||||
title: '操作人',
|
||||
dataIndex: 'operator',
|
||||
width: 120,
|
||||
minWidth: 120,
|
||||
},
|
||||
{
|
||||
title: '操作',
|
||||
dataIndex: 'operator',
|
||||
width: 120,
|
||||
minWidth: 120,
|
||||
},
|
||||
];
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
@ -151,7 +147,7 @@ const columns = [
|
||||
|
||||
:deep(.arco-input-wrapper),
|
||||
:deep(.arco-select-view-single),
|
||||
:deep(.arco-textarea-wrapper),
|
||||
:deep(.ant-input),
|
||||
:deep(.arco-picker),
|
||||
:deep(.arco-select-view-multiple) {
|
||||
border-radius: 4px;
|
||||
|
||||
@ -5,151 +5,143 @@
|
||||
<template>
|
||||
<div class="action-row mb-12px flex justify-between">
|
||||
<div>
|
||||
<a-checkbox
|
||||
<Checkbox
|
||||
v-if="dataSource.length > 0"
|
||||
:model-value="checkedAll"
|
||||
:checked="checkedAll"
|
||||
:indeterminate="indeterminate"
|
||||
class="!pl-13px"
|
||||
@change="handleSelectAll"
|
||||
>全选</a-checkbox
|
||||
@change="(e) => handleSelectAll(e.target.checked)"
|
||||
>全选</Checkbox
|
||||
>
|
||||
</div>
|
||||
<div class="flex items-center">
|
||||
<a-button type="outline" class="w-110px mr-12px" size="medium" @click="handleExport">
|
||||
<template #icon> <icon-download /> </template>
|
||||
<Button type="outline" class="w-110px mr-12px" size="medium" @click="handleExport">
|
||||
<template #icon> <icon-download class="mr-8px" /> </template>
|
||||
<template #default>导出数据</template>
|
||||
</a-button>
|
||||
<a-button type="outline" class="w-110px" size="medium" @click="openCustomColumn">
|
||||
</Button>
|
||||
<Button type="outline" class="w-110px" size="medium" @click="openCustomColumn">
|
||||
<template #icon>
|
||||
<img :src="icon1" width="14" height="14" />
|
||||
<img :src="icon1" width="14" height="14" class="mr-8px" />
|
||||
</template>
|
||||
<template #default>自定义列</template>
|
||||
</a-button>
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<a-table
|
||||
<Table
|
||||
ref="tableRef"
|
||||
:data="dataSource"
|
||||
row-key="id"
|
||||
column-resizable
|
||||
:row-selection="{
|
||||
:dataSource="dataSource"
|
||||
rowKey="id"
|
||||
:rowSelection="{
|
||||
type: 'checkbox',
|
||||
showCheckedAll: true,
|
||||
width: 48,
|
||||
selectedRowKeys: selectedItems,
|
||||
onSelect: handleSelect,
|
||||
onSelectAll: handleSelectAll,
|
||||
}"
|
||||
:selected-keys="selectedItems"
|
||||
:pagination="false"
|
||||
:scroll="{ x: '100%' }"
|
||||
class="account-table w-100% flex-1"
|
||||
bordered
|
||||
@sorter-change="handleSorterChange"
|
||||
@select="handleSelect"
|
||||
@select-all="handleSelectAll"
|
||||
:showSorterTooltip="false"
|
||||
@change="handleTableChange"
|
||||
>
|
||||
<template #empty>
|
||||
<template #emptyText>
|
||||
<NoData />
|
||||
</template>
|
||||
<template #columns>
|
||||
<a-table-column
|
||||
v-for="column in tableColumns"
|
||||
:key="column.dataIndex"
|
||||
:data-index="column.dataIndex"
|
||||
:fixed="column.fixed"
|
||||
:width="column.width"
|
||||
:min-width="column.minWidth"
|
||||
:sortable="column.sortable"
|
||||
:align="column.align"
|
||||
ellipsis
|
||||
tooltip
|
||||
>
|
||||
<template #title>
|
||||
<div class="flex items-center">
|
||||
<img v-if="column.dataIndex === 'ai_evaluate'" width="16" height="16" :src="icon5" class="mr-4px" />
|
||||
<span class="cts mr-4px">{{ column.title }}</span>
|
||||
<a-tooltip v-if="column.tooltip" :content="column.tooltip" position="top">
|
||||
<icon-question-circle class="tooltip-icon color-#737478" size="16" />
|
||||
</a-tooltip>
|
||||
</div>
|
||||
</template>
|
||||
<Column
|
||||
v-for="column in tableColumns"
|
||||
:key="column.dataIndex"
|
||||
:dataIndex="column.dataIndex"
|
||||
:fixed="column.fixed"
|
||||
:width="column.width"
|
||||
:minWidth="column.minWidth"
|
||||
:sorter="column.sortable"
|
||||
:align="column.align"
|
||||
:ellipsis="true"
|
||||
>
|
||||
<template #title>
|
||||
<img v-if="column.dataIndex === 'ai_evaluate'" width="16" height="16" :src="icon5" class="mr-4px" />
|
||||
<span class="cts mr-4px">{{ column.title }}</span>
|
||||
<Tooltip v-if="column.tooltip" :title="column.tooltip" placement="top">
|
||||
<icon-question-circle class="tooltip-icon color-#737478" size="16" />
|
||||
</Tooltip>
|
||||
</template>
|
||||
|
||||
<template v-if="column.dataIndex === 'platform'" #cell="{ record }">
|
||||
<img :src="getMediaAccountPlatformLogo(record.platform)" width="20" height="20" class="rounded-4px" />
|
||||
</template>
|
||||
<template v-else-if="column.dataIndex === 'status'" #cell="{ record }">
|
||||
<StatusBox :item="record" class="w-fit h-28px" />
|
||||
</template>
|
||||
<template v-else-if="column.dataIndex === 'ai_evaluate'" #cell="{ record }">
|
||||
<div class="ai-evaluation-row flex">
|
||||
<template v-if="record.ai_evaluate">
|
||||
<img
|
||||
width="16"
|
||||
height="16"
|
||||
:src="record.ai_evaluate?.status === 0 ? icon2 : record.ai_evaluate?.status === 1 ? icon3 : icon4"
|
||||
class="mr-8px icon"
|
||||
/>
|
||||
<div>
|
||||
<p class="cts">{{ `${record.ai_evaluate?.level} | ${record.ai_evaluate?.advise}` }}。</p>
|
||||
<p class="cts text-12px lh-20px !color-#939499">
|
||||
{{
|
||||
`观看: ${record[`${getPropPrefix(dateType)}view_rate`]}% 点赞: ${
|
||||
record[`${getPropPrefix(dateType)}like_rate`]
|
||||
}%`
|
||||
}}
|
||||
</p>
|
||||
</div>
|
||||
</template>
|
||||
<template v-else>
|
||||
<p class="cts">-</p>
|
||||
</template>
|
||||
</div>
|
||||
</template>
|
||||
<template v-else-if="column.dataIndex === 'like_collect_number'" #cell="{ record }">
|
||||
{{
|
||||
formatNumberShow({
|
||||
value: `${record[`${getPropPrefix(dateType)}like_number`] ?? 0} + ${
|
||||
record[`${getPropPrefix(dateType)}collect_number`] ?? 0
|
||||
}`,
|
||||
showExactValue: true,
|
||||
})
|
||||
}}
|
||||
</template>
|
||||
<template v-else-if="column.dataIndex === 'operation'" #cell="{ record }">
|
||||
<a-button type="outline" size="small" @click="handleDetail(record)">详情</a-button>
|
||||
</template>
|
||||
<template v-if="column.dataIndex === 'platform'" #customRender="{ record }">
|
||||
<img :src="getMediaAccountPlatformLogo(record.platform)" width="20" height="20" class="rounded-4px" />
|
||||
</template>
|
||||
<template v-else-if="column.dataIndex === 'status'" #customRender="{ record }">
|
||||
<StatusBox :item="record" class="w-fit h-28px" />
|
||||
</template>
|
||||
<template v-else-if="column.dataIndex === 'ai_evaluate'" #customRender="{ record }">
|
||||
<div class="ai-evaluation-row flex">
|
||||
<template v-if="record.ai_evaluate">
|
||||
<img
|
||||
width="16"
|
||||
height="16"
|
||||
:src="record.ai_evaluate?.status === 0 ? icon2 : record.ai_evaluate?.status === 1 ? icon3 : icon4"
|
||||
class="mr-8px icon"
|
||||
/>
|
||||
<div>
|
||||
<p class="cts">{{ `${record.ai_evaluate?.level} | ${record.ai_evaluate?.advise}` }}。</p>
|
||||
<p class="cts text-12px lh-20px !color-#939499">
|
||||
{{
|
||||
`观看: ${record[`${getPropPrefix(dateType)}view_rate`]}% 点赞: ${
|
||||
record[`${getPropPrefix(dateType)}like_rate`]
|
||||
}%`
|
||||
}}
|
||||
</p>
|
||||
</div>
|
||||
</template>
|
||||
<template v-else>
|
||||
<p class="cts">-</p>
|
||||
</template>
|
||||
</div>
|
||||
</template>
|
||||
<template v-else-if="column.dataIndex === 'like_collect_number'" #customRender="{ record }">
|
||||
{{
|
||||
formatNumberShow({
|
||||
value: `${record[`${getPropPrefix(dateType)}like_number`] ?? 0} + ${
|
||||
record[`${getPropPrefix(dateType)}collect_number`] ?? 0
|
||||
}`,
|
||||
showExactValue: true,
|
||||
})
|
||||
}}
|
||||
</template>
|
||||
<template v-else-if="column.dataIndex === 'operation'" #customRender="{ record }">
|
||||
<Button type="outline" size="small" @click="handleDetail(record)">详情</Button>
|
||||
</template>
|
||||
|
||||
<template v-else-if="column.isRateField" #cell="{ record }">
|
||||
<div class="flex items-center rate-row justify-end" :class="record[column.dataIndex] > 0 ? 'up' : 'down'">
|
||||
<icon-arrow-up v-if="record[column.dataIndex] > 0" size="16" />
|
||||
<icon-arrow-down v-else size="16" />
|
||||
{{ formatTableField(column, record) }}
|
||||
</div>
|
||||
</template>
|
||||
<template v-else-if="column.dataIndex === 'newest_work_title'" #cell="{ record }">
|
||||
<p class="cts cursor-pointer hover:!color-#6D4CFE">{{ record.newest_work_title }}</p>
|
||||
<p class="cts text-12px lh-20px !color-#939499">
|
||||
{{ exactFormatTime(record.newest_work_published_at) }}
|
||||
</p>
|
||||
</template>
|
||||
<template v-else-if="column.dataIndex === 'second_new_work_title'" #cell="{ record }">
|
||||
<p class="cts cursor-pointer hover:!color-#6D4CFE">{{ record.second_new_work_title }}</p>
|
||||
<p class="cts text-12px lh-20px !color-#939499">
|
||||
{{ exactFormatTime(record.second_new_work_published_at) }}
|
||||
</p>
|
||||
</template>
|
||||
<template v-else-if="column.isRateField" #customRender="{ record }">
|
||||
<div class="flex items-center rate-row justify-end" :class="record[column.dataIndex] > 0 ? 'up' : 'down'">
|
||||
<icon-arrow-up v-if="record[column.dataIndex] > 0" size="16" />
|
||||
<icon-arrow-down v-else size="16" />
|
||||
{{ formatTableField(column, record) }}
|
||||
</div>
|
||||
</template>
|
||||
<template v-else-if="column.dataIndex === 'newest_work_title'" #customRender="{ record }">
|
||||
<p class="cts cursor-pointer hover:!color-#6D4CFE">{{ record.newest_work_title }}</p>
|
||||
<p class="cts text-12px lh-20px !color-#939499">
|
||||
{{ exactFormatTime(record.newest_work_published_at) }}
|
||||
</p>
|
||||
</template>
|
||||
<template v-else-if="column.dataIndex === 'second_new_work_title'" #customRender="{ record }">
|
||||
<p class="cts cursor-pointer hover:!color-#6D4CFE">{{ record.second_new_work_title }}</p>
|
||||
<p class="cts text-12px lh-20px !color-#939499">
|
||||
{{ exactFormatTime(record.second_new_work_published_at) }}
|
||||
</p>
|
||||
</template>
|
||||
|
||||
<template v-else #cell="{ record }">
|
||||
{{ formatTableField(column, record, true) }}
|
||||
</template>
|
||||
|
||||
</a-table-column>
|
||||
<a-table-column data-index="operation" fixed="right" width="100" title="操作">
|
||||
<template #cell="{ record }">
|
||||
<a-button type="outline" size="small" @click="handleDetail(record)">详情</a-button>
|
||||
</template>
|
||||
</a-table-column>
|
||||
</template>
|
||||
</a-table>
|
||||
<template v-else #customRender="{ record }">
|
||||
{{ formatTableField(column, record, true) }}
|
||||
</template>
|
||||
</Column>
|
||||
<Column dataIndex="operation" fixed="right" :width="100" title="操作">
|
||||
<template #customRender="{ record }">
|
||||
<Button type="outline" size="small" @click="handleDetail(record)">详情</Button>
|
||||
</template>
|
||||
</Column>
|
||||
</Table>
|
||||
|
||||
<CustomTableColumnModal
|
||||
ref="customTableColumnModalRef"
|
||||
@ -162,6 +154,8 @@
|
||||
<script setup>
|
||||
import { ref, computed } from 'vue';
|
||||
import { useRouter } from 'vue-router';
|
||||
import { Checkbox, Button, Tooltip, Table } from 'ant-design-vue';
|
||||
const { Column } = Table;
|
||||
|
||||
import { getCustomColumns } from '@/api/all/common';
|
||||
import StatusBox from '@/views/property-marketing/media-account/components/status-select/status-box.tsx';
|
||||
@ -209,7 +203,7 @@ const dateType = computed(() => (props.query.type === 7 ? 'week' : 'month'));
|
||||
const tableColumns = computed(() => {
|
||||
const _result = [];
|
||||
const _columns = getDefaultColumns(dateType.value);
|
||||
console.log({_columns})
|
||||
console.log({ _columns });
|
||||
|
||||
selectedColumns.value.forEach((item) => {
|
||||
const _column = _columns.find((_item) => _item.prop === item);
|
||||
@ -220,30 +214,32 @@ const tableColumns = computed(() => {
|
||||
return _result;
|
||||
});
|
||||
|
||||
const handleSelectAll = (checked) => {
|
||||
if (checked) {
|
||||
selectedItems.value = props.dataSource.map((item) => item.id);
|
||||
} else {
|
||||
selectedItems.value = [];
|
||||
}
|
||||
emit('selectionChange', checked ? selectedItems.value : []);
|
||||
};
|
||||
|
||||
const handleDetail = (record) => {
|
||||
router.push(`/media-account/detail/${record.id}?type=${dateType.value}`);
|
||||
};
|
||||
|
||||
// 处理排序变化
|
||||
const handleSorterChange = (column, order) => {
|
||||
console.log(column, order);
|
||||
emit('sorterChange', column, order === 'ascend' ? 'asc' : 'desc');
|
||||
// 处理表格变化
|
||||
const handleTableChange = (pagination, filters, sorter) => {
|
||||
if (sorter && sorter.field) {
|
||||
emit('sorterChange', sorter.field, sorter.order === 'ascend' ? 'asc' : 'desc');
|
||||
}
|
||||
};
|
||||
|
||||
const handleSelect = (selectedRowKeys, selectedRows) => {
|
||||
selectedItems.value = selectedRowKeys;
|
||||
const handleSelect = (record, selected, selectedRows, nativeEvent) => {
|
||||
selectedItems.value = selectedRows.map((row) => row.id);
|
||||
emit('selectionChange', selectedRows);
|
||||
};
|
||||
|
||||
const handleSelectAll = (selected, selectedRows, changeRows) => {
|
||||
if (selected) {
|
||||
selectedItems.value = props.dataSource.map((item) => item.id);
|
||||
emit('selectionChange', props.dataSource);
|
||||
} else {
|
||||
selectedItems.value = [];
|
||||
emit('selectionChange', []);
|
||||
}
|
||||
};
|
||||
|
||||
const handleExport = () => {
|
||||
emit('export');
|
||||
};
|
||||
|
||||
@ -3,14 +3,15 @@
|
||||
* @Date: 2025-06-30 10:54:49
|
||||
-->
|
||||
<template>
|
||||
<a-modal
|
||||
v-model:visible="visible"
|
||||
<Modal
|
||||
v-model:open="visible"
|
||||
title="自定义列"
|
||||
width="960px"
|
||||
unmountOnClose
|
||||
titleAlign="start"
|
||||
class="custom-table-column-modal-98"
|
||||
@close="close"
|
||||
centered
|
||||
wrapClassName="custom-table-column-modal-98"
|
||||
@cancel="close"
|
||||
>
|
||||
<div class="modal-body">
|
||||
<!-- 左侧分组 -->
|
||||
@ -20,16 +21,16 @@
|
||||
<span class="text">{{ group.label }}</span>
|
||||
</div>
|
||||
<div class="fields">
|
||||
<a-checkbox
|
||||
<Checkbox
|
||||
v-for="option in group.columns"
|
||||
:key="option.value"
|
||||
:model-value="isCheck(option)"
|
||||
:checked="isCheck(option)"
|
||||
:value="option.value"
|
||||
:disabled="option.is_require === ENUM_STATUS.NO"
|
||||
@change="(checked) => onCheckChange(checked, option)"
|
||||
@change="(e) => onCheckChange(e.target.checked, option)"
|
||||
>
|
||||
{{ localFields.find((item) => item.prop === option.value)?.title }}
|
||||
</a-checkbox>
|
||||
</Checkbox>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@ -64,15 +65,16 @@
|
||||
</div>
|
||||
|
||||
<template #footer>
|
||||
<div style="text-align: right">
|
||||
<a-button class="mr-8px" size="medium" @click="close">取消</a-button>
|
||||
<a-button type="primary" size="medium" @click="onSubmit">确定</a-button>
|
||||
<div class="flex">
|
||||
<Button @click="close">取消</Button>
|
||||
<Button type="primary" @click="onSubmit">确定</Button>
|
||||
</div>
|
||||
</template>
|
||||
</a-modal>
|
||||
</Modal>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { Checkbox, Modal, Button } from 'ant-design-vue';
|
||||
import { ref, defineExpose } from 'vue';
|
||||
import { VueDraggable } from 'vue-draggable-plus';
|
||||
|
||||
@ -169,6 +171,7 @@ const removeCheckedField = (value) => {
|
||||
|
||||
// 勾选/取消
|
||||
const onCheckChange = (checked, option) => {
|
||||
console.log(checked, option);
|
||||
if (checked) {
|
||||
checkColumns.value.push(option.value);
|
||||
} else {
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
.custom-table-column-modal-98 {
|
||||
.arco-modal-body {
|
||||
.ant-modal-body {
|
||||
.modal-body {
|
||||
height: 504px;
|
||||
border-radius: 8px;
|
||||
|
||||
@ -8,18 +8,11 @@
|
||||
<div class="filter-row flex">
|
||||
<div class="filter-row-item flex items-center">
|
||||
<span class="label">账号名称</span>
|
||||
<a-input
|
||||
v-model="query.name"
|
||||
placeholder="请搜索..."
|
||||
size="medium"
|
||||
class="!w-240px"
|
||||
allow-clear
|
||||
@change="handleSearch"
|
||||
>
|
||||
<Input v-model:value="query.name" placeholder="请搜索..." class="!w-240px" allowClear @change="handleSearch">
|
||||
<template #prefix>
|
||||
<icon-search />
|
||||
</template>
|
||||
</a-input>
|
||||
</Input>
|
||||
</div>
|
||||
<div class="filter-row-item flex items-center">
|
||||
<span class="label">分组</span>
|
||||
@ -43,37 +36,40 @@
|
||||
<div class="filter-row flex">
|
||||
<div class="filter-row-item flex items-center">
|
||||
<span class="label">时间筛选</span>
|
||||
<a-select v-model="query.type" size="medium" placeholder="全部" class="!w-240px" @change="handleSearch">
|
||||
<template #arrow-icon> <icon-calendar size="16" /> </template>
|
||||
<a-option :value="7" label="近7天">近7天</a-option>
|
||||
<!-- <a-option :value="14" label="近14天">近14天</a-option> -->
|
||||
<a-option :value="30" label="近30天">近30天</a-option>
|
||||
</a-select>
|
||||
<Select v-model:value="query.type" size="middle" placeholder="全部" class="!w-240px" @change="handleSearch">
|
||||
<template #suffixIcon> <icon-calendar size="16" /> </template>
|
||||
<Option :value="7" label="近7天">近7天</Option>
|
||||
<!-- <Option :value="14" label="近14天">近14天</Option> -->
|
||||
<Option :value="30" label="近30天">近30天</Option>
|
||||
</Select>
|
||||
</div>
|
||||
<div class="filter-row-item flex items-center">
|
||||
<a-button type="outline" class="w-84px mr-12px" size="medium" @click="handleSearch">
|
||||
<Button type="primary" ghost class="w-84px mr-12px" @click="handleSearch">
|
||||
<template #icon>
|
||||
<icon-search />
|
||||
<icon-search class="mr-8px" />
|
||||
</template>
|
||||
<template #default>搜索</template>
|
||||
</a-button>
|
||||
<a-button class="w-84px" size="medium" @click="handleReset">
|
||||
</Button>
|
||||
<Button class="w-84px" @click="handleReset">
|
||||
<template #icon>
|
||||
<icon-refresh />
|
||||
<icon-refresh class="mr-8px" />
|
||||
</template>
|
||||
<template #default>重置</template>
|
||||
</a-button>
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { reactive, defineEmits, defineProps } from 'vue';
|
||||
import { Button, Input, Select } from 'ant-design-vue';
|
||||
import { reactive, defineEmits, defineProps, onMounted, nextTick, ref } from 'vue';
|
||||
import { fetchAccountGroups, fetchAccountOperators } from '@/api/all/propertyMarketing';
|
||||
import StatusSelect from '@/views/property-marketing/media-account/components/status-select';
|
||||
import CommonSelect from '@/components/common-select';
|
||||
|
||||
const { Option } = Select;
|
||||
|
||||
const props = defineProps({
|
||||
query: {
|
||||
type: Object,
|
||||
@ -81,7 +77,7 @@ const props = defineProps({
|
||||
},
|
||||
});
|
||||
|
||||
const emits = defineEmits('onSearch', 'onReset', 'update:query');
|
||||
const emits = defineEmits(['onSearch', 'onReset', 'update:query']);
|
||||
|
||||
const groups = ref([]);
|
||||
const operators = ref([]);
|
||||
|
||||
@ -37,8 +37,8 @@ export const CARD_FIELDS = [
|
||||
|
||||
export const INITIAL_QUERY = {
|
||||
name: '',
|
||||
status: '',
|
||||
operator_id: '',
|
||||
status: undefined,
|
||||
operator_id: undefined,
|
||||
group_ids: [],
|
||||
type: 7,
|
||||
column: '',
|
||||
|
||||
@ -9,9 +9,9 @@
|
||||
<div class="top flex h-64px py-10px justify-between items-center">
|
||||
<div class="flex items-center">
|
||||
<p class="text-18px font-400 lh-26px color-#211F24 mr-4px title">数据总览</p>
|
||||
<a-tooltip content="展示所筛选的账号的信息汇总">
|
||||
<Tooltip title="展示所筛选的账号的信息汇总">
|
||||
<icon-question-circle size="16" class="color-#737478" />
|
||||
</a-tooltip>
|
||||
</Tooltip>
|
||||
</div>
|
||||
</div>
|
||||
<div class="overview-row flex">
|
||||
@ -19,15 +19,15 @@
|
||||
<div class="flex items-center mb-8px">
|
||||
<img :src="item.icon" width="20" height="20" class="mr-8px" />
|
||||
<p class="label color-#211F24">{{ item.label }}</p>
|
||||
<a-tooltip v-if="item.tooltip" :content="item.tooltip">
|
||||
<Tooltip v-if="item.tooltip" :title="item.tooltip">
|
||||
<img :src="icon1" width="14" height="14" class="ml-4px" />
|
||||
</a-tooltip>
|
||||
</Tooltip>
|
||||
</div>
|
||||
<span class="value color-#211F24 ml-32px">{{ formatNumberShow(overviewData[item.prop]) }}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class=" bg-#fff rounded-8px mb-16px">
|
||||
<div class="bg-#fff rounded-8px mb-16px">
|
||||
<FilterBlock v-model:query="query" @onSearch="handleSearch" @onReset="handleReset" />
|
||||
</div>
|
||||
<div class="table-wrap bg-#fff rounded-8px px-24px py-24px flex flex-col">
|
||||
@ -40,16 +40,15 @@
|
||||
@sorterChange="handleSorterChange"
|
||||
/>
|
||||
<div v-if="pageInfo.total > 0" class="pagination-row">
|
||||
<a-pagination
|
||||
<Pagination
|
||||
:total="pageInfo.total"
|
||||
size="mini"
|
||||
show-total
|
||||
show-jumper
|
||||
show-page-size
|
||||
size="small"
|
||||
:showTotal="(total, range) => `共 ${total} 条`"
|
||||
showSizeChanger
|
||||
showQuickJumper
|
||||
:current="pageInfo.page"
|
||||
:page-size="pageInfo.page_size"
|
||||
:pageSize="pageInfo.page_size"
|
||||
@change="onPageChange"
|
||||
@page-size-change="onPageSizeChange"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
@ -60,6 +59,7 @@
|
||||
import FilterBlock from './components/filter-block';
|
||||
import AccountTable from './components/account-table';
|
||||
|
||||
import { Tooltip, Pagination } from 'ant-design-vue';
|
||||
import { getAccountBoardOverview, getAccountBoardList, postAccountBoardExport } from '@/api/all/propertyMarketing';
|
||||
import { formatNumberShow } from '@/utils/tools';
|
||||
import { INITIAL_QUERY, CARD_FIELDS } from './constants';
|
||||
@ -99,8 +99,9 @@ const getData = async () => {
|
||||
}
|
||||
};
|
||||
|
||||
const onPageChange = (current) => {
|
||||
const onPageChange = (current, pageSize) => {
|
||||
pageInfo.value.page = current;
|
||||
pageInfo.value.page_size = pageSize;
|
||||
getData();
|
||||
};
|
||||
|
||||
|
||||
@ -3,7 +3,7 @@
|
||||
* @Date: 2025-06-28 12:58:25
|
||||
-->
|
||||
<template>
|
||||
<div class="account-info-wrap bg-#fff rounded-8px px-24px mb-16px">
|
||||
<div class="account-info-wrap bg-#fff rounded-8px px-24px mb-16px">
|
||||
<div class="title-row">
|
||||
<span class="cts !text-18px !lh-26px title">账号信息</span>
|
||||
</div>
|
||||
@ -47,9 +47,9 @@
|
||||
<template v-else>
|
||||
<div class="flex items-center mb-4px">
|
||||
<p class="cts !color-#737478 !mr-4px">{{ field.title }}</p>
|
||||
<a-tooltip v-if="field.tooltip" :content="field.tooltip" position="top">
|
||||
<Tooltip v-if="field.tooltip" :title="field.tooltip" position="top">
|
||||
<icon-question-circle class="tooltip-icon color-#737478" size="16" />
|
||||
</a-tooltip>
|
||||
</Tooltip>
|
||||
</div>
|
||||
<p class="cts">
|
||||
<template v-if="field.type === 'status'">
|
||||
@ -60,10 +60,10 @@
|
||||
<div v-for="(tag, index) in detailData.tags.slice(0, 2)" :key="index" class="tag-box">
|
||||
<span class="text">{{ tag.name }}</span>
|
||||
</div>
|
||||
<a-tooltip
|
||||
<Tooltip
|
||||
v-if="detailData.tags.length > 2"
|
||||
position="top"
|
||||
:content="
|
||||
:title="
|
||||
detailData.tags
|
||||
.slice(2)
|
||||
.map((v) => v.name)
|
||||
@ -73,7 +73,7 @@
|
||||
<div class="tag-box">
|
||||
<span class="text">{{ `+${detailData.tags.length - 2}` }}</span>
|
||||
</div>
|
||||
</a-tooltip>
|
||||
</Tooltip>
|
||||
</div>
|
||||
<span class="cts" v-else>-</span>
|
||||
</template>
|
||||
@ -88,7 +88,12 @@
|
||||
}}
|
||||
</template>
|
||||
<template v-else-if="field.dataIndex === 'platform'">
|
||||
<img :src="getMediaAccountPlatformLogo(detailData.platform)" width="16" height="16" class="rounded-4px" />
|
||||
<img
|
||||
:src="getMediaAccountPlatformLogo(detailData.platform)"
|
||||
width="16"
|
||||
height="16"
|
||||
class="rounded-4px"
|
||||
/>
|
||||
</template>
|
||||
<template v-else-if="['last_authorized_at', 'last_synced_at'].includes(field.dataIndex)">
|
||||
{{ exactFormatTime(detailData[field.dataIndex], 'YYYY-MM-DD HH:mm:ss', 'YYYY-MM-DD HH:mm:ss') }}
|
||||
@ -132,6 +137,7 @@
|
||||
<script setup>
|
||||
import { useRoute } from 'vue-router';
|
||||
|
||||
import { Tooltip } from 'ant-design-vue';
|
||||
import { formatTableField, formatNumberShow, exactFormatTime } from '@/utils/tools';
|
||||
import { getMediaAccountPlatformLogo } from '@/utils/platform';
|
||||
import { getAccountInfoFields } from '../../constants';
|
||||
|
||||
@ -18,7 +18,7 @@ export const TABLE_COLUMNS = [
|
||||
{
|
||||
title: '笔记标题',
|
||||
dataIndex: 'title',
|
||||
width: 240,
|
||||
width: 280,
|
||||
fixed: 'left',
|
||||
},
|
||||
{
|
||||
@ -30,42 +30,42 @@ export const TABLE_COLUMNS = [
|
||||
{
|
||||
title: '曝光量',
|
||||
dataIndex: 'exposure_number',
|
||||
width: 180,
|
||||
width: 160,
|
||||
tooltip: '内容被展示给用户的总次数,不代表用户实际观看。',
|
||||
align: 'right',
|
||||
},
|
||||
{
|
||||
title: '观看量',
|
||||
dataIndex: 'view_number',
|
||||
width: 180,
|
||||
width: 160,
|
||||
tooltip: '用户点击内容并实际观看的次数,是内容实际触达的重要指标。',
|
||||
align: 'right',
|
||||
},
|
||||
{
|
||||
title: '点赞量',
|
||||
dataIndex: 'like_number',
|
||||
width: 180,
|
||||
width: 160,
|
||||
tooltip: '单篇笔记获得的点赞总数,反映用户喜好程度。',
|
||||
align: 'right',
|
||||
},
|
||||
{
|
||||
title: '收藏量',
|
||||
dataIndex: 'collect_number',
|
||||
width: 180,
|
||||
width: 160,
|
||||
tooltip: '用户将内容保存到收藏夹的次数,代表内容被认可为“值得保留”。',
|
||||
align: 'right',
|
||||
},
|
||||
{
|
||||
title: '评论数',
|
||||
dataIndex: 'comment_number',
|
||||
width: 180,
|
||||
width: 160,
|
||||
tooltip: '内容下方用户留言的总数,体现用户参与度与讨论热度。',
|
||||
align: 'right',
|
||||
},
|
||||
{
|
||||
title: '分享量',
|
||||
dataIndex: 'share_number',
|
||||
width: 180,
|
||||
width: 160,
|
||||
tooltip: '内容被转发或分享至其他平台或私信的次数,代表外扩传播意愿。',
|
||||
align: 'right',
|
||||
},
|
||||
|
||||
@ -3,121 +3,115 @@
|
||||
* @Date: 2025-06-28 12:58:09
|
||||
-->
|
||||
<template>
|
||||
<div class="note-table-wrap bg-#fff rounded-8px px-24px flex-1 flex flex-col">
|
||||
<div class="note-table-wrap bg-#fff rounded-8px px-24px flex-1 flex flex-col">
|
||||
<div class="title-row">
|
||||
<div class="flex items-center">
|
||||
<span class="cts !text-18px !lh-26px mr-4px title">笔记详情</span>
|
||||
<a-tooltip content="展示笔记层级的详细数据,如曝光、互动等,是内容精细分析入口。">
|
||||
<Tooltip title="展示笔记层级的详细数据,如曝光、互动等,是内容精细分析入口。">
|
||||
<icon-question-circle size="16" class="color-#737478" />
|
||||
</a-tooltip>
|
||||
</Tooltip>
|
||||
</div>
|
||||
</div>
|
||||
<div class="filter-row flex my-16px">
|
||||
<div class="filter-row-item flex items-center">
|
||||
<span class="label">笔记标题</span>
|
||||
<a-space size="medium" class="w-240px">
|
||||
<a-input v-model="query.title" placeholder="请搜索..." size="medium" allow-clear @change="handleSearch">
|
||||
<template #prefix>
|
||||
<icon-search />
|
||||
</template>
|
||||
</a-input>
|
||||
</a-space>
|
||||
<Input v-model:value="query.title" class="!w-240px" placeholder="请搜索..." allowClear @change="handleSearch">
|
||||
<template #prefix>
|
||||
<icon-search />
|
||||
</template>
|
||||
</Input>
|
||||
</div>
|
||||
<div class="filter-row-item flex items-center">
|
||||
<span class="label">发布日期</span>
|
||||
<a-space size="medium" class="w-260px">
|
||||
<a-range-picker
|
||||
v-model="published_at"
|
||||
size="medium"
|
||||
allow-clear
|
||||
format="YYYY-MM-DD"
|
||||
class="w-100%"
|
||||
@change="onDateChange"
|
||||
/>
|
||||
</a-space>
|
||||
<DatePicker.RangePicker
|
||||
v-model:value="published_at"
|
||||
size="medium"
|
||||
class="!w-260px"
|
||||
allow-clear
|
||||
format="YYYY-MM-DD"
|
||||
@change="onDateChange"
|
||||
/>
|
||||
</div>
|
||||
<a-button type="outline" class="w-84px mr-12px" size="medium" @click="handleSearch">
|
||||
<Button type="primary" ghost class="w-84px mr-12px" @click="handleSearch">
|
||||
<template #icon>
|
||||
<icon-search />
|
||||
<icon-search class="mr-8px" />
|
||||
</template>
|
||||
<template #default>搜索</template>
|
||||
</a-button>
|
||||
<a-button class="w-84px" size="medium" @click="handleReset">
|
||||
</Button>
|
||||
<Button class="w-84px" @click="handleReset">
|
||||
<template #icon>
|
||||
<icon-refresh />
|
||||
<icon-refresh class="mr-8px" />
|
||||
</template>
|
||||
<template #default>重置</template>
|
||||
</a-button>
|
||||
</Button>
|
||||
</div>
|
||||
<a-table
|
||||
:data="dataSource"
|
||||
row-key="id"
|
||||
<Table
|
||||
:dataSource="dataSource"
|
||||
rowKey="id"
|
||||
:pagination="false"
|
||||
:scroll="{ x: '100%' }"
|
||||
class="w-100%"
|
||||
bordered
|
||||
column-resizable
|
||||
:showSorterTooltip="false"
|
||||
>
|
||||
<template #empty>
|
||||
<Table.Column
|
||||
v-for="column in TABLE_COLUMNS"
|
||||
:key="column.dataIndex"
|
||||
:dataIndex="column.dataIndex"
|
||||
:fixed="column.fixed"
|
||||
:width="column.width"
|
||||
:minWidth="column.minWidth"
|
||||
:sortable="column.sortable"
|
||||
:align="column.align"
|
||||
:ellipsis="true"
|
||||
>
|
||||
<template #title>
|
||||
<span class="cts mr-4px">{{ column.title }}</span>
|
||||
<Tooltip v-if="column.tooltip" :title="column.tooltip" placement="top">
|
||||
<icon-question-circle class="tooltip-icon color-#737478" size="16" />
|
||||
</Tooltip>
|
||||
</template>
|
||||
<template #customRender="{ record }">
|
||||
<template v-if="column.dataIndex === 'published_at'">
|
||||
{{ exactFormatTime(record.published_at) }}
|
||||
</template>
|
||||
<template v-else-if="column.dataIndex === 'exposure_number'">
|
||||
{{ formatNumberShow({ value: record.view_number * 10, showExactValue: true }) }}
|
||||
</template>
|
||||
<template v-else-if="column.dataIndex === 'title'">
|
||||
<TextoverTips :context="record.title" />
|
||||
</template>
|
||||
<template v-else>
|
||||
{{ formatTableField(column, record, true) }}
|
||||
</template>
|
||||
</template>
|
||||
</Table.Column>
|
||||
<template #emptyText>
|
||||
<NoData />
|
||||
</template>
|
||||
<template #columns>
|
||||
<a-table-column
|
||||
v-for="column in TABLE_COLUMNS"
|
||||
:key="column.dataIndex"
|
||||
:data-index="column.dataIndex"
|
||||
:fixed="column.fixed"
|
||||
:width="column.width"
|
||||
:min-width="column.minWidth"
|
||||
:sortable="column.sortable"
|
||||
:align="column.align"
|
||||
ellipsis
|
||||
tooltip
|
||||
>
|
||||
<template #title>
|
||||
<div class="flex items-center">
|
||||
<span class="cts mr-4px">{{ column.title }}</span>
|
||||
<a-tooltip v-if="column.tooltip" :content="column.tooltip" position="top">
|
||||
<icon-question-circle class="tooltip-icon color-#737478" size="16" />
|
||||
</a-tooltip>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<template #cell="{ record }">
|
||||
<template v-if="column.dataIndex === 'published_at'">
|
||||
{{ exactFormatTime(record.published_at) }}
|
||||
</template>
|
||||
<template v-else-if="column.dataIndex === 'exposure_number'">
|
||||
{{ formatNumberShow({ value: record.view_number * 10, showExactValue: true }) }}
|
||||
</template>
|
||||
<template v-else>
|
||||
{{ formatTableField(column, record, true) }}
|
||||
</template>
|
||||
</template>
|
||||
</a-table-column>
|
||||
</template>
|
||||
</a-table>
|
||||
</Table>
|
||||
<div v-if="pageInfo.total > 0" class="pagination-row mb-24px">
|
||||
<a-pagination
|
||||
<Pagination
|
||||
:total="pageInfo.total"
|
||||
size="mini"
|
||||
show-total
|
||||
show-jumper
|
||||
show-page-size
|
||||
size="small"
|
||||
:showTotal="(total, range) => `共 ${total} 条`"
|
||||
showSizeChanger
|
||||
showQuickJumper
|
||||
:current="pageInfo.page"
|
||||
:page-size="pageInfo.page_size"
|
||||
:pageSize="pageInfo.page_size"
|
||||
@change="onPageChange"
|
||||
@page-size-change="onPageSizeChange"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { Button, Input, Tooltip, Table, Pagination, DatePicker } from 'ant-design-vue';
|
||||
import { TABLE_COLUMNS, INITIAL_QUERY, INITIAL_PAGE_INFO } from './constants';
|
||||
import { useRoute } from 'vue-router';
|
||||
import { formatTableField, exactFormatTime, formatNumberShow } from '@/utils/tools';
|
||||
import { getMediaAccountBoardWorks } from '@/api/all/propertyMarketing';
|
||||
import TextoverTips from '@/components/text-over-tips/index.vue';
|
||||
|
||||
const route = useRoute();
|
||||
const id = route.params.id;
|
||||
@ -148,8 +142,9 @@ const onDateChange = (value) => {
|
||||
handleSearch();
|
||||
};
|
||||
|
||||
const onPageChange = (current) => {
|
||||
const onPageChange = (current, pageSize) => {
|
||||
pageInfo.value.page = current;
|
||||
pageInfo.value.page_size = pageSize;
|
||||
getData();
|
||||
};
|
||||
|
||||
|
||||
@ -3,27 +3,27 @@
|
||||
* @Date: 2025-06-26 17:44:16
|
||||
-->
|
||||
<template>
|
||||
<a-modal
|
||||
v-model:visible="visible"
|
||||
<Modal
|
||||
v-model:open="visible"
|
||||
:title="isBatch ? '批量删除账号' : '删除账号'"
|
||||
width="400px"
|
||||
modal-class="account-manage-modal"
|
||||
@close="onClose"
|
||||
wrapClassName="account-manage-modal"
|
||||
@cancel="onClose"
|
||||
centered
|
||||
>
|
||||
<div class="flex items-center">
|
||||
<img :src="icon1" width="20" height="20" class="mr-12px" />
|
||||
<span>确认删除 {{ accountName }} 这个账号吗?</span>
|
||||
</div>
|
||||
<template #footer>
|
||||
<a-button size="large" @click="onClose">取消</a-button>
|
||||
<a-button type="primary" class="ml-16px danger-btn" status="danger" size="large" @click="onDelete"
|
||||
>确认删除</a-button
|
||||
>
|
||||
<Button @click="onClose">取消</Button>
|
||||
<Button type="primary" class="ml-16px" danger @click="onDelete">确认删除</Button>
|
||||
</template>
|
||||
</a-modal>
|
||||
</Modal>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { Modal, Button, message } from 'ant-design-vue';
|
||||
import { ref } from 'vue';
|
||||
import { deleteMediaAccount, batchDeleteMediaAccounts } from '@/api/all/propertyMarketing';
|
||||
import icon1 from '@/assets/img/media-account/icon-warn-1.png';
|
||||
@ -56,7 +56,7 @@ async function onDelete() {
|
||||
const _params = isBatch.value ? { ids: accountId.value } : accountId.value;
|
||||
const { code } = await _fn(_params);
|
||||
if (code === 200) {
|
||||
AMessage.success('删除成功');
|
||||
message.success('删除成功');
|
||||
isBatch.value ? emits('batchUpdate') : emits('update');
|
||||
onClose();
|
||||
}
|
||||
|
||||
@ -3,7 +3,9 @@ import {
|
||||
EnumErrorStatus,
|
||||
getStatusInfo,
|
||||
} from '@/views/property-marketing/media-account/components/status-select/status-box';
|
||||
import { Dropdown, Doption, Button, Tooltip } from '@arco-design/web-vue';
|
||||
import { Dropdown, Menu } from 'ant-design-vue';
|
||||
const { Item: MenuItem } = Menu;
|
||||
import { Tooltip, Button } from 'ant-design-vue';
|
||||
export default defineComponent({
|
||||
name: 'FooterBtn',
|
||||
props: {
|
||||
@ -21,37 +23,37 @@ export default defineComponent({
|
||||
|
||||
const renderEditDoption = () => {
|
||||
return (
|
||||
<Doption class="color-#211F24" onClick={() => emit('openEdit', props.item)}>
|
||||
<MenuItem class="color-#211F24" onClick={() => emit('openEdit', props.item)}>
|
||||
编辑
|
||||
</Doption>
|
||||
</MenuItem>
|
||||
);
|
||||
};
|
||||
const renderReauthorizeDoption = (text = '重新授权') => {
|
||||
return (
|
||||
<Doption class="color-#211F24" onClick={() => emit('handleReauthorize', props.item)}>
|
||||
<MenuItem class="color-#211F24" onClick={() => emit('handleReauthorize', props.item)}>
|
||||
{text}
|
||||
</Doption>
|
||||
</MenuItem>
|
||||
);
|
||||
};
|
||||
const renderPauseDoption = () => {
|
||||
return (
|
||||
<Doption class="color-#211F24" onClick={() => emit('handlePause', props.item)}>
|
||||
<MenuItem class="color-#211F24" onClick={() => emit('handlePause', props.item)}>
|
||||
暂停同步
|
||||
</Doption>
|
||||
</MenuItem>
|
||||
);
|
||||
};
|
||||
const renderUpdateBtn = () => {
|
||||
return (
|
||||
<Button type="outline" size="mini" onClick={() => emit('syncData', props.item)}>
|
||||
<Button type="primary" ghost size="small" onClick={() => emit('syncData', props.item)}>
|
||||
更新数据
|
||||
</Button>
|
||||
);
|
||||
};
|
||||
const renderDeleteDoption = () => {
|
||||
return (
|
||||
<Doption class="color-#F64B31" onClick={() => emit('openDelete', props.item)}>
|
||||
<MenuItem class="color-#F64B31" onClick={() => emit('openDelete', props.item)}>
|
||||
删除
|
||||
</Doption>
|
||||
</MenuItem>
|
||||
);
|
||||
};
|
||||
const renderNormal = () => {
|
||||
@ -61,17 +63,17 @@ export default defineComponent({
|
||||
trigger="hover"
|
||||
v-slots={{
|
||||
default: () => (
|
||||
<Button type="outline" class="mr-8px" size="mini">
|
||||
<Button type="primary" ghost class="mr-8px" size="small">
|
||||
更多
|
||||
</Button>
|
||||
),
|
||||
content: () => (
|
||||
<>
|
||||
overlay: () => (
|
||||
<Menu>
|
||||
{renderEditDoption()}
|
||||
{renderReauthorizeDoption()}
|
||||
{renderPauseDoption()}
|
||||
{renderDeleteDoption()}
|
||||
</>
|
||||
</Menu>
|
||||
),
|
||||
}}
|
||||
></Dropdown>
|
||||
@ -86,19 +88,19 @@ export default defineComponent({
|
||||
trigger="hover"
|
||||
v-slots={{
|
||||
default: () => (
|
||||
<Button type="outline" class="mr-8px" size="mini">
|
||||
<Button type="primary" ghost class="mr-8px" size="small">
|
||||
更多
|
||||
</Button>
|
||||
),
|
||||
content: () => (
|
||||
<>
|
||||
overlay: () => (
|
||||
<Menu>
|
||||
{renderEditDoption()}
|
||||
{renderDeleteDoption()}
|
||||
</>
|
||||
</Menu>
|
||||
),
|
||||
}}
|
||||
></Dropdown>
|
||||
<Button type="outline" size="mini" onClick={() => emit('handleReauthorize', props.item)}>
|
||||
<Button type="primary" ghost size="small" onClick={() => emit('handleReauthorize', props.item)}>
|
||||
开启同步
|
||||
</Button>
|
||||
</>
|
||||
@ -115,15 +117,15 @@ export default defineComponent({
|
||||
return renderUpdateBtn();
|
||||
} else if ([EnumErrorStatus.REQUEST, EnumErrorStatus.FREEZE].includes(error_status)) {
|
||||
return (
|
||||
<Tooltip content={statusInfo.value.disabledBtnTooltip}>
|
||||
<Button type="outline" size="mini" disabled>
|
||||
<Tooltip title={statusInfo.value.disabledBtnTooltip}>
|
||||
<Button type="primary" ghost size="small" disabled>
|
||||
重新授权
|
||||
</Button>
|
||||
</Tooltip>
|
||||
);
|
||||
} else {
|
||||
return (
|
||||
<Button type="outline" size="mini" onClick={() => emit('handleReauthorize', props.item)}>
|
||||
<Button type="primary" ghost size="small" onClick={() => emit('handleReauthorize', props.item)}>
|
||||
{isUnauthorized ? '去授权' : '重新授权'}
|
||||
</Button>
|
||||
);
|
||||
@ -135,17 +137,17 @@ export default defineComponent({
|
||||
trigger="hover"
|
||||
v-slots={{
|
||||
default: () => (
|
||||
<Button type="outline" class="mr-8px" size="mini">
|
||||
<Button type="primary" ghost class="mr-8px" size="small">
|
||||
更多
|
||||
</Button>
|
||||
),
|
||||
content: () => (
|
||||
<>
|
||||
overlay: () => (
|
||||
<Menu>
|
||||
{renderEditDoption()}
|
||||
{isMissing && renderReauthorizeDoption()}
|
||||
{renderPauseDoption()}
|
||||
{renderDeleteDoption()}
|
||||
</>
|
||||
</Menu>
|
||||
),
|
||||
}}
|
||||
></Dropdown>
|
||||
|
||||
@ -4,24 +4,21 @@
|
||||
-->
|
||||
<template>
|
||||
<div class="card-container">
|
||||
<a-spin
|
||||
<Spin
|
||||
v-for="(item, index) in dataSource"
|
||||
:key="index"
|
||||
:loading="isSyncing(item)"
|
||||
:spinning="isSyncing(item)"
|
||||
tip="更新数据中..."
|
||||
class="card-item"
|
||||
:class="{
|
||||
checked: isSelected(item),
|
||||
}"
|
||||
:wrapperClassName="`card-item ${isSelected(item) ? 'checked' : ''}`"
|
||||
>
|
||||
<template #icon>
|
||||
<icon-sync size="24" />
|
||||
</template>
|
||||
<a-checkbox :model-value="isSelected(item)" :value="item.id" @change="toggleSelect(item)"></a-checkbox>
|
||||
<Checkbox :checked="isSelected(item)" :value="item.id" @change="toggleSelect(item)" class="relative top--2px"></Checkbox>
|
||||
<div class="ml-8px flex-1">
|
||||
<a-tooltip content="点击查看账号详情">
|
||||
<Tooltip title="点击查看账号详情">
|
||||
<p class="name cursor-pointer hover:!color-#6d4cfe" @click="goDetail(item)">{{ item.name || '-' }}</p>
|
||||
</a-tooltip>
|
||||
</Tooltip>
|
||||
<div class="field-row">
|
||||
<span class="label">状态</span>
|
||||
<StatusBox :item="item" />
|
||||
@ -74,10 +71,10 @@
|
||||
<span class="label">所属项目</span>
|
||||
<span v-if="!item.projects.length" class="cts">-</span>
|
||||
<div v-else class="flex items-center">
|
||||
<a-tooltip
|
||||
<Tooltip
|
||||
v-if="item.projects.length > 2"
|
||||
position="bottom"
|
||||
:content="
|
||||
placement="bottom"
|
||||
:title="
|
||||
item.projects
|
||||
.slice(2)
|
||||
.map((v) => v.name)
|
||||
@ -87,7 +84,7 @@
|
||||
<div class="tag-box">
|
||||
<span class="text">{{ `+${item.projects.length - 2}` }}</span>
|
||||
</div>
|
||||
</a-tooltip>
|
||||
</Tooltip>
|
||||
|
||||
<div v-for="(project, index) in item.projects.slice(0, 2)" :key="index" class="tag-box">
|
||||
<span class="text">{{ project.name }}</span>
|
||||
@ -102,10 +99,10 @@
|
||||
<span class="label">标签</span>
|
||||
<span v-if="!item.tags.length" class="cts">-</span>
|
||||
<div v-else class="flex items-center">
|
||||
<a-tooltip
|
||||
<Tooltip
|
||||
v-if="item.tags.length > 2"
|
||||
position="bottom"
|
||||
:content="
|
||||
placement="bottom"
|
||||
:title="
|
||||
item.tags
|
||||
.slice(2)
|
||||
.map((v) => v.name)
|
||||
@ -115,7 +112,7 @@
|
||||
<div class="tag-box">
|
||||
<span class="text">{{ `+${item.tags.length - 2}` }}</span>
|
||||
</div>
|
||||
</a-tooltip>
|
||||
</Tooltip>
|
||||
|
||||
<div v-for="(tag, index) in item.tags.slice(0, 2)" :key="index" class="tag-box">
|
||||
<span class="text">{{ tag.name }}</span>
|
||||
@ -139,13 +136,13 @@
|
||||
<span class="name !mb-0">{{ getErrorStatusText(item) }}</span>
|
||||
</div>
|
||||
<div class="flex items-center">
|
||||
<a-button type="outline" class="mr-8px" size="mini" @click="handleCancel(item)">取消</a-button>
|
||||
<a-button type="outline" size="mini" @click="handleConfirm(item)" v-if="showConfirmBtn(item)">{{
|
||||
<Button type="primary" ghost class="mr-8px" size="small" @click="handleCancel(item)">取消</Button>
|
||||
<Button type="primary" ghost size="small" @click="handleConfirm(item)" v-if="showConfirmBtn(item)">{{
|
||||
getConfirmBtnText(item)
|
||||
}}</a-button>
|
||||
}}</Button>
|
||||
</div>
|
||||
</div>
|
||||
</a-spin>
|
||||
</Spin>
|
||||
<PauseAccountPatchModal ref="pauseAccountPatchModalRef" @success="emits('update')" />
|
||||
<ReauthorizeAccountModal ref="reauthorizeAccountModalRef" @update="emits('update')" />
|
||||
<AuthorizedAccountModal ref="authorizedAccountModalRef" @update="emits('update')" />
|
||||
@ -154,6 +151,7 @@
|
||||
|
||||
<script setup>
|
||||
import { defineProps, ref, computed, inject } from 'vue';
|
||||
import { Checkbox, Button, Tooltip, Spin } from 'ant-design-vue';
|
||||
import { useRouter } from 'vue-router';
|
||||
import { deleteSyncStatus } from '@/api/all/propertyMarketing';
|
||||
import { exactFormatTime } from '@/utils/tools';
|
||||
|
||||
@ -3,19 +3,27 @@
|
||||
* @Date: 2025-06-27 14:41:20
|
||||
-->
|
||||
<template>
|
||||
<a-modal v-model:visible="visible" title="暂停同步" width="400px" modal-class="account-manage-modal" @close="onClose">
|
||||
<Modal
|
||||
v-model:open="visible"
|
||||
title="暂停同步"
|
||||
centered
|
||||
width="400px"
|
||||
wrapClassName="account-manage-modal"
|
||||
@cancel="onClose"
|
||||
>
|
||||
<div class="flex items-center">
|
||||
<img :src="icon1" width="20" height="20" class="mr-12px" />
|
||||
<span>确认暂停同步 “{{ accountName }}” 这个账号的数据吗?</span>
|
||||
</div>
|
||||
<template #footer>
|
||||
<a-button size="large" @click="onClose">取消</a-button>
|
||||
<a-button type="primary" class="ml-16px" size="large" @click="onConfirm">确定</a-button>
|
||||
<Button size="large" @click="onClose">取消</Button>
|
||||
<Button type="primary" class="ml-16px" size="large" @click="onConfirm">确定</Button>
|
||||
</template>
|
||||
</a-modal>
|
||||
</Modal>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { Button, Modal, message } from 'ant-design-vue';
|
||||
import { ref } from 'vue';
|
||||
import { pausePatchAccount } from '@/api/all/propertyMarketing';
|
||||
import icon1 from '@/assets/img/media-account/icon-warn-1.png';
|
||||
@ -44,7 +52,7 @@ const open = (record) => {
|
||||
async function onConfirm() {
|
||||
const { code } = await pausePatchAccount(accountId.value);
|
||||
if (code === 200) {
|
||||
AMessage.success('暂停成功');
|
||||
message.success('暂停成功');
|
||||
emits('success');
|
||||
onClose();
|
||||
}
|
||||
|
||||
@ -4,13 +4,17 @@
|
||||
// grid-template-rows: repeat(2, 1fr); /* 2行 */
|
||||
grid-template-columns: repeat(4, 1fr); /* 4列 */
|
||||
gap: 20px;
|
||||
:deep(.ant-spin-container) {
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
display: flex;
|
||||
align-items: flex-start;
|
||||
}
|
||||
.card-item {
|
||||
border-radius: 8px;
|
||||
// border: 1px solid var(--BG-300, #e6e6e8);
|
||||
background: var(--BG-white, #fff);
|
||||
padding: 12px 16px 16px;
|
||||
display: flex;
|
||||
align-items: flex-start;
|
||||
position: relative;
|
||||
.name {
|
||||
color: var(--Text-1, #211f24);
|
||||
|
||||
@ -5,20 +5,19 @@
|
||||
<script lang="jsx">
|
||||
import { ref, computed } from 'vue';
|
||||
import {
|
||||
Button,
|
||||
Modal,
|
||||
Form,
|
||||
FormItem,
|
||||
Input,
|
||||
RadioGroup,
|
||||
Radio,
|
||||
Upload,
|
||||
Button,
|
||||
Switch,
|
||||
Input,
|
||||
message,
|
||||
Tooltip,
|
||||
Notification,
|
||||
Message as AMessage,
|
||||
Textarea,
|
||||
} from '@arco-design/web-vue';
|
||||
Upload,
|
||||
Switch,
|
||||
} from 'ant-design-vue';
|
||||
const { TextArea } = Input;
|
||||
import AuthorizedAccountModal from '../authorized-account-modal';
|
||||
// import ImportPromptModal from '../import-prompt-modal';
|
||||
import StatusBox from '@/views/property-marketing/media-account/components/status-select/status-box.tsx';
|
||||
@ -97,15 +96,14 @@ export default {
|
||||
mobile: [
|
||||
{
|
||||
required: true,
|
||||
message: '请填写手机号',
|
||||
trigger: ['blur', 'change'],
|
||||
},
|
||||
{
|
||||
validator: (value, callback) => {
|
||||
validator: (_rule, value) => {
|
||||
if (!value) {
|
||||
return Promise.reject('请填写手机号');
|
||||
}
|
||||
if (!/^1[3-9]\d{9}$/.test(value)) {
|
||||
callback('手机号格式不正确');
|
||||
return Promise.reject('手机号格式不正确');
|
||||
} else {
|
||||
callback();
|
||||
return Promise.resolve();
|
||||
}
|
||||
},
|
||||
trigger: ['blur', 'change'],
|
||||
@ -145,10 +143,9 @@ export default {
|
||||
}
|
||||
};
|
||||
function handleUpload(option) {
|
||||
const { fileItem } = option;
|
||||
uploadStatus.value = UploadStatus.WAITING;
|
||||
file.value = fileItem.file;
|
||||
fileName.value = fileItem.name;
|
||||
file.value = option.file;
|
||||
fileName.value = option.file.name;
|
||||
}
|
||||
function removeFile() {
|
||||
fileName.value = '';
|
||||
@ -198,7 +195,7 @@ export default {
|
||||
const handleBatchImport = async () => {
|
||||
try {
|
||||
if (!file.value) {
|
||||
AMessage.warning('请上传要导入的文件');
|
||||
message.warning('请上传要导入的文件');
|
||||
return;
|
||||
}
|
||||
|
||||
@ -244,7 +241,7 @@ export default {
|
||||
const handleEditAccount = async () => {
|
||||
const { code } = await putMediaAccounts({ id: id.value, ...form.value });
|
||||
if (code === 200) {
|
||||
AMessage.success('修改成功');
|
||||
message.success('修改成功');
|
||||
emit('update');
|
||||
onClose();
|
||||
}
|
||||
@ -254,14 +251,12 @@ export default {
|
||||
handleBatchImport();
|
||||
return;
|
||||
}
|
||||
formRef.value.validate(async (errors) => {
|
||||
if (!errors) {
|
||||
if (isCustomCookie.value && !form.value.cookie) {
|
||||
AMessage.warning('请填写Cookie值');
|
||||
return;
|
||||
}
|
||||
isEdit.value ? handleEditAccount() : handleAddAccount();
|
||||
formRef.value.validate().then(async () => {
|
||||
if (isCustomCookie.value && !form.value.cookie) {
|
||||
message.warning('请填写Cookie值');
|
||||
return;
|
||||
}
|
||||
isEdit.value ? handleEditAccount() : handleAddAccount();
|
||||
});
|
||||
}
|
||||
const startAuthorized = (id, platform) => {
|
||||
@ -288,18 +283,27 @@ export default {
|
||||
|
||||
return () => (
|
||||
<Modal
|
||||
v-model:visible={visible.value}
|
||||
v-model:open={visible.value}
|
||||
title={isEdit.value ? '编辑账号' : '添加账号'}
|
||||
modal-class="add-account-modal"
|
||||
wrapClassName="add-account-modal"
|
||||
width="500px"
|
||||
mask-closable={false}
|
||||
onClose={onClose}
|
||||
centered
|
||||
maskClosable={false}
|
||||
onCancel={onClose}
|
||||
footer={null}
|
||||
>
|
||||
<Form ref={formRef} model={form.value} rules={rules} layout="horizontal" auto-label-width>
|
||||
<Form
|
||||
ref={formRef}
|
||||
model={form.value}
|
||||
rules={rules}
|
||||
layout="horizontal"
|
||||
labelAlign="right"
|
||||
labelCol={{ span: 4 }}
|
||||
wrapperCol={{ span: 20 }}
|
||||
>
|
||||
{!isEdit.value && (
|
||||
<FormItem label="上传方式" required>
|
||||
<RadioGroup v-model={uploadType.value}>
|
||||
<RadioGroup v-model:value={uploadType.value}>
|
||||
<Radio value="manual">手动添加账号</Radio>
|
||||
<Radio value="batch">批量导入账号</Radio>
|
||||
</RadioGroup>
|
||||
@ -312,19 +316,14 @@ export default {
|
||||
<Upload
|
||||
ref={uploadRef}
|
||||
action="/"
|
||||
draggable
|
||||
custom-request={handleUpload}
|
||||
customRequest={handleUpload}
|
||||
accept=".xlsx,.xls"
|
||||
show-file-list={false}
|
||||
showUploadList={false}
|
||||
>
|
||||
{{
|
||||
'upload-button': () => (
|
||||
<div class="upload-box">
|
||||
<span class="text mb-4px">点击或拖拽文件到此处上传</span>
|
||||
<span class="tip">支持 xls, xlsx格式</span>
|
||||
</div>
|
||||
),
|
||||
}}
|
||||
<div class="upload-box">
|
||||
<span class="text mb-4px">点击或拖拽文件到此处上传</span>
|
||||
<span class="tip">支持 xls, xlsx格式</span>
|
||||
</div>
|
||||
</Upload>
|
||||
) : (
|
||||
<div class="flex items-center">
|
||||
@ -356,22 +355,22 @@ export default {
|
||||
<>
|
||||
{isEdit.value && (
|
||||
<>
|
||||
<FormItem label="账号名称" field="name">
|
||||
<Input v-model={form.value.name} placeholder="请输入..." size="large" disabled />
|
||||
<FormItem label="账号名称" name="name">
|
||||
<Input v-model:value={form.value.name} placeholder="请输入..." size="large" disabled />
|
||||
</FormItem>
|
||||
<FormItem label="账号ID" field="account_id">
|
||||
<Input v-model={form.value.account_id} placeholder="请输入..." size="large" disabled />
|
||||
<FormItem label="账号ID" name="account_id">
|
||||
<Input v-model:value={form.value.account_id} placeholder="请输入..." size="large" disabled />
|
||||
</FormItem>
|
||||
<FormItem label="状态" field="status">
|
||||
<FormItem label="状态" name="status">
|
||||
<StatusBox item={form.value} />
|
||||
</FormItem>
|
||||
</>
|
||||
)}
|
||||
<FormItem label="手机号码" field="mobile" required>
|
||||
<Input v-model={form.value.mobile} placeholder="请输入..." size="large" />
|
||||
<FormItem label="手机号码" name="mobile" required>
|
||||
<Input v-model:value={form.value.mobile} placeholder="请输入..." size="large" />
|
||||
</FormItem>
|
||||
<FormItem label="运营人员" field="operator_name" required>
|
||||
<Input v-model={form.value.operator_name} placeholder="请输入..." class="w-240px" size="large" />
|
||||
<FormItem label="运营人员" name="operator_name" required>
|
||||
<Input v-model:value={form.value.operator_name} placeholder="请输入..." class="w-240px" size="large" />
|
||||
</FormItem>
|
||||
<FormItem label="运营平台" required={!isEdit.value}>
|
||||
{isEdit.value ? (
|
||||
@ -398,7 +397,7 @@ export default {
|
||||
height="24"
|
||||
/>
|
||||
) : (
|
||||
<RadioGroup v-model={form.value.platform}>
|
||||
<RadioGroup v-model:value={form.value.platform}>
|
||||
<Radio value={1}>小红书</Radio>
|
||||
<Radio value={0}>抖音</Radio>
|
||||
<Radio value={2}>B站</Radio>
|
||||
@ -409,8 +408,8 @@ export default {
|
||||
</RadioGroup>
|
||||
)}
|
||||
</FormItem>
|
||||
<FormItem label="号码持有人" field="holder_name">
|
||||
<Input v-model={form.value.holder_name} placeholder="请输入..." class="w-240px" size="large" />
|
||||
<FormItem label="号码持有人" name="holder_name">
|
||||
<Input v-model:value={form.value.holder_name} placeholder="请输入..." class="w-240px" size="large" />
|
||||
</FormItem>
|
||||
<FormItem label="所属项目">
|
||||
<CommonSelect
|
||||
@ -448,10 +447,10 @@ export default {
|
||||
}}
|
||||
>
|
||||
<Textarea
|
||||
v-model={form.value.end_work_link}
|
||||
v-model:value={form.value.end_work_link}
|
||||
placeholder="请输入笔记链接。若无需输入,填写 “无” "
|
||||
size="large"
|
||||
auto-size={{ minRows: 3, maxRows: 5 }}
|
||||
autoSize={{ minRows: 3, maxRows: 5 }}
|
||||
/>
|
||||
</FormItem>
|
||||
<FormItem
|
||||
@ -463,12 +462,12 @@ export default {
|
||||
<Switch v-model={isCustomCookie.value} size="large" />
|
||||
</FormItem>
|
||||
{isCustomCookie.value && (
|
||||
<FormItem label="" field="cookie">
|
||||
<Textarea
|
||||
v-model={form.value.cookie}
|
||||
<FormItem label=" " name="cookie">
|
||||
<TextArea
|
||||
v-model:value={form.value.cookie}
|
||||
placeholder="请输入..."
|
||||
size="large"
|
||||
auto-size={{ minRows: 5, maxRows: 8 }}
|
||||
autoSize={{ minRows: 5, maxRows: 8 }}
|
||||
/>
|
||||
</FormItem>
|
||||
)}
|
||||
|
||||
@ -4,7 +4,7 @@
|
||||
.w-240px {
|
||||
width: 240px !important;
|
||||
}
|
||||
.arco-modal-body {
|
||||
.ant-modal-body {
|
||||
.upload-block {
|
||||
width: 100%;
|
||||
.dt {
|
||||
@ -36,15 +36,8 @@
|
||||
}
|
||||
}
|
||||
}
|
||||
.arco-upload-drag {
|
||||
height: 120px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
.arco-icon {
|
||||
margin-bottom: 16px;
|
||||
}
|
||||
.ant-upload {
|
||||
width: 100%;
|
||||
}
|
||||
.upload-box {
|
||||
display: flex;
|
||||
@ -77,13 +70,13 @@
|
||||
}
|
||||
}
|
||||
}
|
||||
.upload-dragger {
|
||||
border: 1px dashed #d9d9d9;
|
||||
padding: 24px 0;
|
||||
text-align: center;
|
||||
background: #fafafa;
|
||||
cursor: pointer;
|
||||
}
|
||||
// .upload-dragger {
|
||||
// border: 1px dashed #d9d9d9;
|
||||
// padding: 24px 0;
|
||||
// text-align: center;
|
||||
// background: #fafafa;
|
||||
// cursor: pointer;
|
||||
// }
|
||||
.upload-error {
|
||||
color: #f53f3f;
|
||||
margin-left: 8px;
|
||||
|
||||
@ -3,24 +3,25 @@
|
||||
* @Date: 2025-06-25 17:51:46
|
||||
-->
|
||||
<template>
|
||||
<a-modal
|
||||
v-model:visible="visible"
|
||||
<Modal
|
||||
v-model:open="visible"
|
||||
width="480px"
|
||||
title="授权账号"
|
||||
modal-class="authorized-account-modal"
|
||||
:mask-closable="false"
|
||||
:footer="modalState !== MODAL_STATE.LOADING"
|
||||
@close="close"
|
||||
centered
|
||||
wrapClassName="authorized-account-modal"
|
||||
:maskClosable="false"
|
||||
:footer="modalState === MODAL_STATE.LOADING ? null : footer"
|
||||
@cancel="close"
|
||||
>
|
||||
<div class="flex flex-col items-center">
|
||||
<!-- 加载中状态 -->
|
||||
<template v-if="modalState === MODAL_STATE.LOADING">
|
||||
<a-progress
|
||||
<Progress
|
||||
:percent="progress"
|
||||
color="#6D4CFE"
|
||||
trackColor="#E6E6E8"
|
||||
size="large"
|
||||
:stroke-width="4"
|
||||
strokeColor="#6D4CFE"
|
||||
trailColor="#E6E6E8"
|
||||
size="default"
|
||||
:strokeWidth="4"
|
||||
type="circle"
|
||||
/>
|
||||
<p class="s2 mt-16px">数据同步和初始化中,请勿关闭窗口。</p>
|
||||
@ -40,7 +41,7 @@
|
||||
<!-- 二维码加载中或失败 -->
|
||||
<template v-if="modalState === MODAL_STATE.QR_LOADING || modalState === MODAL_STATE.QR_FAILED">
|
||||
<div class="relative w-160px h-160px">
|
||||
<a-image :src="icon1" width="160" height="160" />
|
||||
<Image :src="icon1" :width="160" :height="160" />
|
||||
<div class="absolute top-0 left-0 z-2 w-full h-full flex flex-col items-center justify-center">
|
||||
<img
|
||||
v-if="modalState === MODAL_STATE.QR_FAILED"
|
||||
@ -62,7 +63,7 @@
|
||||
</div>
|
||||
</template>
|
||||
<!-- 正常二维码 -->
|
||||
<a-image v-else :src="qrCodeUrl" width="160" height="160" />
|
||||
<Image v-else :src="qrCodeUrl" :width="160" :height="160" />
|
||||
<!-- 二维码失效遮罩 -->
|
||||
<div v-if="modalState === MODAL_STATE.QR_EXPIRED" class="mask cursor-pointer" @click="handleRefreshQrCode">
|
||||
<icon-refresh size="24" class="mb-13px" />
|
||||
@ -76,24 +77,24 @@
|
||||
</div>
|
||||
|
||||
<template #footer>
|
||||
<a-button v-if="modalState === MODAL_STATE.QR_READY" size="large" @click="handleRefreshQrCode">
|
||||
<Button v-if="modalState === MODAL_STATE.QR_READY" size="large" @click="handleRefreshQrCode">
|
||||
重新生成
|
||||
</a-button>
|
||||
<a-button v-if="[MODAL_STATE.SUCCESS, MODAL_STATE.FAILED].includes(modalState)" size="large" @click="close">
|
||||
</Button>
|
||||
<Button v-if="[MODAL_STATE.SUCCESS, MODAL_STATE.FAILED].includes(modalState)" size="large" @click="close">
|
||||
取消
|
||||
</a-button>
|
||||
<a-button type="primary" size="large" @click="handleOk">
|
||||
</Button>
|
||||
<Button type="primary" size="large" @click="handleOk">
|
||||
{{ confirmBtnText }}
|
||||
</a-button>
|
||||
</Button>
|
||||
</template>
|
||||
</a-modal>
|
||||
</Modal>
|
||||
|
||||
<SyncDataModal ref="syncDataModalRef" />
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { defineExpose, ref, computed } from 'vue';
|
||||
import { Message as AMessage } from '@arco-design/web-vue';
|
||||
import { Button, Modal, message, Image, Progress } from 'ant-design-vue';
|
||||
import { getAuthorizedImage, getMediaAccountsAuthorizedStatus } from '@/api/all/propertyMarketing';
|
||||
import SyncDataModal from '../sync-data-modal';
|
||||
|
||||
@ -262,12 +263,12 @@ const getAuthorizedStatus = async () => {
|
||||
const startFakeProgressPolling = () => {
|
||||
clearFakeProgressTimer();
|
||||
progressTimer = setInterval(() => {
|
||||
if (modalState.value === MODAL_STATE.LOADING && progress.value < 0.99) {
|
||||
const step = Math.random() * 0.04 + 0.01;
|
||||
progress.value = Math.min(progress.value + step, 0.99);
|
||||
if (modalState.value === MODAL_STATE.LOADING && progress.value < 99) {
|
||||
const step = Math.random() * 4 + 1;
|
||||
progress.value = Math.min(progress.value + step, 99);
|
||||
progress.value = Number(progress.value.toFixed(2));
|
||||
} else if (modalState.value === MODAL_STATE.LOADING && progress.value >= 0.99) {
|
||||
progress.value = 0.99; // 卡在99%
|
||||
} else if (modalState.value === MODAL_STATE.LOADING && progress.value >= 99) {
|
||||
progress.value = 99; // 卡在99%
|
||||
} else {
|
||||
clearFakeProgressTimer();
|
||||
clearStatusPollingTimer();
|
||||
@ -305,7 +306,7 @@ const handleOk = () => {
|
||||
|
||||
// 二维码还在加载中
|
||||
if (modalState.value === MODAL_STATE.QR_LOADING) {
|
||||
AMessage.warning('二维码生成中,请稍等');
|
||||
message.warning('二维码生成中,请稍等');
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@ -3,73 +3,87 @@
|
||||
* @Date: 2025-06-27 09:35:49
|
||||
-->
|
||||
<template>
|
||||
<a-modal
|
||||
v-model:visible="visible"
|
||||
<Modal
|
||||
v-model:open="visible"
|
||||
title="批量分组"
|
||||
modal-class="batch-group-modal"
|
||||
wrapClassName="batch-group-modal"
|
||||
width="800px"
|
||||
:mask-closable="false"
|
||||
:maskClosable="false"
|
||||
centered
|
||||
>
|
||||
<div class="mb-16px t1">
|
||||
{{ `已选${accountGroupList.length}个账号` }}
|
||||
</div>
|
||||
<a-form ref="formRef" :model="form" layout="horizontal" auto-label-width>
|
||||
<a-form-item label="编辑方式" required>
|
||||
<a-radio-group v-model="editType">
|
||||
<a-radio value="all">
|
||||
<Form ref="formRef" :model="form" layout="horizontal">
|
||||
<FormItem label="编辑方式" required>
|
||||
<Radio.Group v-model:value="editType">
|
||||
<Radio value="all">
|
||||
<div class="flex items-center">
|
||||
<span>统一编辑</span>
|
||||
<a-tooltip content="原分组将被清除,统一加入新分组。">
|
||||
<Tooltip title="原分组将被清除,统一加入新分组。">
|
||||
<img :src="icon1" alt="icon" class="ml-2px" width="14" height="14" />
|
||||
</a-tooltip>
|
||||
</Tooltip>
|
||||
</div>
|
||||
</a-radio>
|
||||
<a-radio value="each">分别编辑</a-radio>
|
||||
</a-radio-group>
|
||||
</a-form-item>
|
||||
<a-form-item label="选择分组" required>
|
||||
</Radio>
|
||||
<Radio value="each">分别编辑</Radio>
|
||||
</Radio.Group>
|
||||
</FormItem>
|
||||
<FormItem label="选择分组" required>
|
||||
<template v-if="editType === 'all'">
|
||||
<div class="flex items-center w-100%">
|
||||
<CommonSelect v-model="form.group_id" :options="groupOptions" :multiple="false" class="flex-1" />
|
||||
</div>
|
||||
</template>
|
||||
</a-form-item>
|
||||
</FormItem>
|
||||
|
||||
<!-- 分别编辑 -->
|
||||
<template v-if="editType === 'each'">
|
||||
<a-table :data="accountGroupList" :pagination="false" row-key="id" class="w-100%" column-resizable>
|
||||
<template #columns>
|
||||
<a-table-column title="账号名称" data-index="name" width="200">
|
||||
<template #cell="{ record }">
|
||||
<span>{{ record.name || '-' }}</span>
|
||||
</template>
|
||||
</a-table-column>
|
||||
<a-table-column title="选择分组" data-index="group_id">
|
||||
<template #cell="{ record }">
|
||||
<div class="flex items-center w-100%">
|
||||
<CommonSelect v-model="record.group_id" :options="groupOptions" :multiple="false" />
|
||||
</div>
|
||||
</template>
|
||||
</a-table-column>
|
||||
<Table
|
||||
:dataSource="accountGroupList"
|
||||
:columns="columns"
|
||||
:pagination="false"
|
||||
rowKey="id"
|
||||
bordered
|
||||
:showSorterTooltip="false"
|
||||
@resizeColumn="handleResizeColumn"
|
||||
>
|
||||
<template #bodyCell="{ column, record }">
|
||||
<template v-if="column.dataIndex === 'name'">
|
||||
<span>{{ record.name || '-' }}</span>
|
||||
</template>
|
||||
<template v-else-if="column.dataIndex === 'group_id'">
|
||||
<div class="flex items-center w-100%">
|
||||
<CommonSelect v-model="record.group_id" :options="groupOptions" :multiple="false" class="w-full" />
|
||||
</div>
|
||||
</template>
|
||||
</template>
|
||||
</a-table>
|
||||
</Table>
|
||||
</template>
|
||||
</a-form>
|
||||
</Form>
|
||||
<template #footer>
|
||||
<a-button size="large" @click="onClose">取消</a-button>
|
||||
<a-button type="primary" size="large" @click="onSubmit">确定</a-button>
|
||||
<Button @click="onClose">取消</Button>
|
||||
<Button type="primary" @click="onSubmit">确定</Button>
|
||||
</template>
|
||||
</a-modal>
|
||||
</Modal>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref, reactive } from 'vue';
|
||||
import { ref, reactive, computed } from 'vue';
|
||||
import { Modal, Form, FormItem, Radio, Tooltip, Button, Table, message } from 'ant-design-vue';
|
||||
import { fetchAccountGroups, batchPutGroup } from '@/api/all/propertyMarketing';
|
||||
import CommonSelect from '@/components/common-select';
|
||||
|
||||
import icon1 from '@/assets/img/icon-question.png';
|
||||
|
||||
// [{id, name, group_id: null}]
|
||||
const columns = ref([
|
||||
{ title: '账号名称', dataIndex: 'name', width: 100, minWidth: 100, resizable: true },
|
||||
{ title: '选择分组', dataIndex: 'group_id' },
|
||||
]);
|
||||
|
||||
const handleResizeColumn = (w, col) => {
|
||||
const idx = columns.value.findIndex((c) => c.dataIndex === col.dataIndex);
|
||||
if (idx !== -1) columns.value[idx].width = w;
|
||||
};
|
||||
|
||||
const emits = defineEmits(['update']);
|
||||
const visible = ref(false);
|
||||
@ -102,18 +116,17 @@ const getTags = async () => {
|
||||
|
||||
const onClose = () => {
|
||||
visible.value = false;
|
||||
form.group_id = null;
|
||||
};
|
||||
|
||||
const onSubmit = async () => {
|
||||
if (isAllEdit.value) {
|
||||
if (form.group_id === null) {
|
||||
AMessage.error('请选择分组');
|
||||
message.error('请选择分组');
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
if (accountGroupList.value.some((item) => item.group_id === null)) {
|
||||
AMessage.error('请选择分组');
|
||||
message.error('请选择分组');
|
||||
return;
|
||||
}
|
||||
}
|
||||
@ -126,7 +139,7 @@ const onSubmit = async () => {
|
||||
// 这里处理批量标签的提交逻辑
|
||||
const { code } = await batchPutGroup({ media_accounts });
|
||||
if (code === 200) {
|
||||
AMessage.success('设置分组成功');
|
||||
message.success('设置分组成功');
|
||||
emits('update');
|
||||
visible.value = false;
|
||||
}
|
||||
|
||||
@ -2,7 +2,7 @@
|
||||
|
||||
.batch-group-modal {
|
||||
border-radius: 8px;
|
||||
.arco-modal-body {
|
||||
.ant-modal-body {
|
||||
// min-height: 200px;
|
||||
.t1 {
|
||||
color: var(--Text-3, #737478);
|
||||
|
||||
@ -3,87 +3,85 @@
|
||||
* @Date: 2025-06-27 09:35:49
|
||||
-->
|
||||
<template>
|
||||
<a-modal
|
||||
v-model:visible="visible"
|
||||
<Modal
|
||||
v-model:open="visible"
|
||||
title="批量标签"
|
||||
modal-class="batch-tag-modal"
|
||||
wrapClassName="batch-tag-modal"
|
||||
width="800px"
|
||||
:mask-closable="false"
|
||||
centered
|
||||
:maskClosable="false"
|
||||
>
|
||||
<div class="mb-16px t1">
|
||||
{{ `已选${accountTagList.length}个账号` }}
|
||||
</div>
|
||||
<a-form ref="formRef" :model="form" layout="horizontal" auto-label-width>
|
||||
<a-form-item label="编辑方式" required>
|
||||
<a-radio-group v-model="editType">
|
||||
<a-radio value="all">
|
||||
<Form ref="formRef" :model="form" layout="horizontal" auto-label-width>
|
||||
<FormItem label="编辑方式" required>
|
||||
<RadioGroup v-model:value="editType">
|
||||
<Radio value="all">
|
||||
<div class="flex items-center">
|
||||
<span>统一编辑</span>
|
||||
<a-tooltip content="原标签将被清除,统一为新标签。">
|
||||
<Tooltip title="原标签将被清除,统一为新标签。">
|
||||
<img :src="icon1" alt="icon" class="ml-2px" width="14" height="14" />
|
||||
</a-tooltip>
|
||||
</Tooltip>
|
||||
</div>
|
||||
</a-radio>
|
||||
<a-radio value="each">分别编辑</a-radio>
|
||||
</a-radio-group>
|
||||
</a-form-item>
|
||||
<a-form-item label="选择标签" required>
|
||||
</Radio>
|
||||
<Radio value="each">分别编辑</Radio>
|
||||
</RadioGroup>
|
||||
</FormItem>
|
||||
<FormItem label="选择标签" required>
|
||||
<template v-if="editType === 'all'">
|
||||
<div class="flex items-center w-100%">
|
||||
<a-select
|
||||
v-model="form.tags"
|
||||
<Select
|
||||
v-model:value="form.tags"
|
||||
:options="tagOptions"
|
||||
multiple
|
||||
allow-create
|
||||
mode="tags"
|
||||
placeholder="请输入标签,回车键可直接添加..."
|
||||
:limit="5"
|
||||
:max-tag-count="5"
|
||||
class="flex-1"
|
||||
@create="handleCreateTag"
|
||||
@search="handleCreateTag"
|
||||
/>
|
||||
<span class="ml-12px">{{ `${form.tags.length}/5` }}</span>
|
||||
</div>
|
||||
</template>
|
||||
</a-form-item>
|
||||
</FormItem>
|
||||
|
||||
<!-- 分别编辑 -->
|
||||
<template v-if="editType === 'each'">
|
||||
<a-table :data="accountTagList" :pagination="false" row-key="id" class="w-100%" column-resizable>
|
||||
<template #columns>
|
||||
<a-table-column title="账号名称" data-index="name" width="200">
|
||||
<template #cell="{ record }">
|
||||
<span>{{ record.name || '-' }}</span>
|
||||
</template>
|
||||
</a-table-column>
|
||||
<a-table-column title="选择标签" data-index="tags">
|
||||
<template #cell="{ record, rowIndex }">
|
||||
<div class="flex items-center w-100%">
|
||||
<a-select
|
||||
v-model="record.tags"
|
||||
:options="tagOptions"
|
||||
multiple
|
||||
allow-create
|
||||
placeholder="请输入标签,回车键可直接添加..."
|
||||
:limit="5"
|
||||
style="width: 90%"
|
||||
@create="(val) => handleCreateTag(val, rowIndex)"
|
||||
/>
|
||||
<span class="tag-count ml-8px">{{ record.tags.length }}/5</span>
|
||||
</div>
|
||||
</template>
|
||||
</a-table-column>
|
||||
</template>
|
||||
</a-table>
|
||||
<Table :dataSource="accountTagList" :pagination="false" rowKey="id" class="w-100%">
|
||||
<Table.Column title="账号名称" dataIndex="name" :width="200">
|
||||
<template #customRender="{ record }">
|
||||
<span>{{ record.name || '-' }}</span>
|
||||
</template>
|
||||
</Table.Column>
|
||||
<Table.Column title="选择标签" dataIndex="tags">
|
||||
<template #customRender="{ record, index }">
|
||||
<div class="flex items-center w-100%">
|
||||
<Select
|
||||
v-model:value="record.tags"
|
||||
:options="tagOptions"
|
||||
mode="tags"
|
||||
placeholder="请输入标签,回车键可直接添加..."
|
||||
:max-tag-count="5"
|
||||
class="!w-full"
|
||||
@search="(val) => handleCreateTag(val, index)"
|
||||
/>
|
||||
<span class="tag-count ml-8px">{{ record.tags.length }}/5</span>
|
||||
</div>
|
||||
</template>
|
||||
</Table.Column>
|
||||
</Table>
|
||||
</template>
|
||||
</a-form>
|
||||
</Form>
|
||||
<template #footer>
|
||||
<a-button size="large" @click="onClose">取消</a-button>
|
||||
<a-button type="primary" size="large" @click="onSubmit">确定</a-button>
|
||||
<Button size="large" @click="onClose">取消</Button>
|
||||
<Button type="primary" size="large" @click="onSubmit">确定</Button>
|
||||
</template>
|
||||
</a-modal>
|
||||
</Modal>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref, reactive } from 'vue';
|
||||
import { Button, Form, FormItem, Modal, Radio, RadioGroup, Select, Table, Tooltip, message } from 'ant-design-vue';
|
||||
import { fetchAccountTags, batchPutTag } from '@/api/all/propertyMarketing';
|
||||
|
||||
import icon1 from '@/assets/img/icon-question.png';
|
||||
@ -143,12 +141,12 @@ const onClose = () => {
|
||||
const onSubmit = async () => {
|
||||
if (isAllEdit.value) {
|
||||
if (form.tags.length === 0) {
|
||||
AMessage.error('请输入标签');
|
||||
message.error('请输入标签');
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
if (accountTagList.value.some((item) => item.tags.length === 0)) {
|
||||
AMessage.error('请输入标签');
|
||||
message.error('请输入标签');
|
||||
return;
|
||||
}
|
||||
}
|
||||
@ -160,7 +158,7 @@ const onSubmit = async () => {
|
||||
console.log({ media_accounts });
|
||||
const { code } = await batchPutTag({ media_accounts });
|
||||
if (code === 200) {
|
||||
AMessage.success('设置标签成功');
|
||||
message.success('设置标签成功');
|
||||
emits('update');
|
||||
visible.value = false;
|
||||
}
|
||||
|
||||
@ -2,7 +2,7 @@
|
||||
|
||||
.batch-tag-modal {
|
||||
border-radius: 8px;
|
||||
.arco-modal-body {
|
||||
.ant-modal-body {
|
||||
// min-height: 200px;
|
||||
.t1 {
|
||||
color: var(--Text-3, #737478);
|
||||
|
||||
@ -8,86 +8,73 @@
|
||||
<div class="filter-row flex">
|
||||
<div class="filter-row-item">
|
||||
<span class="label">账号名称/ID/手机号</span>
|
||||
<a-space size="medium">
|
||||
<a-input
|
||||
v-model="query.search"
|
||||
class="w-240px"
|
||||
placeholder="请搜索..."
|
||||
size="medium"
|
||||
allow-clear
|
||||
@change="handleSearch"
|
||||
>
|
||||
<template #prefix>
|
||||
<icon-search />
|
||||
</template>
|
||||
</a-input>
|
||||
</a-space>
|
||||
<Input v-model:value="query.search" class="w-240px" placeholder="请搜索..." allowClear @change="handleSearch">
|
||||
<template #prefix>
|
||||
<icon-search />
|
||||
</template>
|
||||
</Input>
|
||||
</div>
|
||||
<div class="filter-row-item">
|
||||
<span class="label">状态</span>
|
||||
<a-space class="w-180px">
|
||||
<StatusSelect v-model="query.status" @change="handleSearch" />
|
||||
</a-space>
|
||||
<StatusSelect v-model="query.status" @change="handleSearch" class="w-180px" />
|
||||
</div>
|
||||
<div class="filter-row-item">
|
||||
<span class="label">平台</span>
|
||||
<a-space class="w-160px">
|
||||
<a-select v-model="query.platform" size="medium" placeholder="全部" allow-clear @change="handleSearch">
|
||||
<a-option
|
||||
v-for="(item, index) in MEDIA_ACCOUNT_PLATFORMS"
|
||||
:key="index"
|
||||
:value="item.value"
|
||||
:label="item.label"
|
||||
>{{ item.label }}</a-option
|
||||
>
|
||||
</a-select>
|
||||
</a-space>
|
||||
<Select
|
||||
v-model:value="query.platform"
|
||||
class="w-160px"
|
||||
size="middle"
|
||||
placeholder="全部"
|
||||
allowClear
|
||||
@change="handleSearch"
|
||||
>
|
||||
<Option
|
||||
v-for="(item, index) in MEDIA_ACCOUNT_PLATFORMS"
|
||||
:key="index"
|
||||
:value="item.value"
|
||||
:label="item.label"
|
||||
>{{ item.label }}</Option
|
||||
>
|
||||
</Select>
|
||||
</div>
|
||||
<div class="filter-row-item">
|
||||
<span class="label">运营人员</span>
|
||||
<a-space class="w-160px">
|
||||
<CommonSelect
|
||||
v-model="query.operator_id"
|
||||
allowSearch
|
||||
:multiple="false"
|
||||
:options="operators"
|
||||
@change="handleSearch"
|
||||
/>
|
||||
</a-space>
|
||||
<CommonSelect
|
||||
class="w-160px"
|
||||
v-model="query.operator_id"
|
||||
allowSearch
|
||||
:multiple="false"
|
||||
:options="operators"
|
||||
@change="handleSearch"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="filter-row">
|
||||
<div class="filter-row-item">
|
||||
<span class="label">分组</span>
|
||||
<a-space class="w-200px">
|
||||
<CommonSelect v-model="query.group_ids" multiple :options="groups" @change="handleSearch" />
|
||||
</a-space>
|
||||
<CommonSelect v-model="query.group_ids" multiple :options="groups" @change="handleSearch" class="!w-200px" />
|
||||
</div>
|
||||
<div class="filter-row-item">
|
||||
<span class="label">所属项目</span>
|
||||
<a-space class="w-200px">
|
||||
<CommonSelect v-model="query.project_ids" :options="projects" @change="handleSearch" />
|
||||
</a-space>
|
||||
<CommonSelect v-model="query.project_ids" :options="projects" @change="handleSearch" class="!w-200px" />
|
||||
</div>
|
||||
<div class="filter-row-item">
|
||||
<span class="label">标签</span>
|
||||
<a-space class="w-320px">
|
||||
<CommonSelect v-model="query.tag_ids" :options="tags" @change="handleSearch" />
|
||||
</a-space>
|
||||
<CommonSelect v-model="query.tag_ids" :options="tags" @change="handleSearch" class="!w-320px" />
|
||||
</div>
|
||||
<div class="filter-row-item">
|
||||
<a-button type="outline" class="w-84px mr-12px" size="medium" @click="handleSearch">
|
||||
<Button type="primary" ghost class="w-84px mr-12px" @click="handleSearch">
|
||||
<template #icon>
|
||||
<icon-search />
|
||||
<icon-search class="mr-8px" />
|
||||
</template>
|
||||
<template #default>搜索</template>
|
||||
</a-button>
|
||||
<a-button class="w-84px" size="medium" @click="handleReset">
|
||||
</Button>
|
||||
<Button class="w-84px" @click="handleReset">
|
||||
<template #icon>
|
||||
<icon-refresh />
|
||||
<icon-refresh class="mr-8px" />
|
||||
</template>
|
||||
<template #default>重置</template>
|
||||
</a-button>
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@ -95,6 +82,8 @@
|
||||
|
||||
<script setup>
|
||||
import { reactive, defineEmits, defineProps } from 'vue';
|
||||
import { Button, Input, Select } from 'ant-design-vue';
|
||||
const { Option } = Select;
|
||||
import {
|
||||
fetchAccountTags,
|
||||
getProjectList,
|
||||
@ -114,7 +103,7 @@ const props = defineProps({
|
||||
},
|
||||
});
|
||||
|
||||
const emits = defineEmits('onSearch', 'onReset', 'update:query');
|
||||
const emits = defineEmits(['onSearch', 'onReset', 'update:query']);
|
||||
|
||||
const tags = ref([]);
|
||||
const groups = ref([]);
|
||||
|
||||
@ -3,27 +3,29 @@
|
||||
* @Date: 2025-06-26 11:44:17
|
||||
-->
|
||||
<template>
|
||||
<a-modal
|
||||
v-model:visible="visible"
|
||||
<Modal
|
||||
v-model:open="visible"
|
||||
:title="isEdit ? '编辑分组' : '添加新分组'"
|
||||
modal-class="account-manage-modal"
|
||||
wrapClassName="group-manage-modal"
|
||||
width="400px"
|
||||
@close="onClose"
|
||||
centered
|
||||
@cancel="onClose"
|
||||
>
|
||||
<a-form ref="formRef" :model="form" :rules="rules" layout="horizontal" auto-label-width>
|
||||
<a-form-item :label="isEdit ? '分组名称' : '新分组名称'" field="name" required>
|
||||
<a-input v-model="form.name" placeholder="请输入…" />
|
||||
</a-form-item>
|
||||
</a-form>
|
||||
<Form ref="formRef" :model="form" :rules="rules" layout="horizontal" auto-label-width>
|
||||
<FormItem :label="isEdit ? '分组名称' : '新分组名称'" name="name" required>
|
||||
<Input v-model:value="form.name" placeholder="请输入…" />
|
||||
</FormItem>
|
||||
</Form>
|
||||
<template #footer>
|
||||
<a-button @click="onClose">取消</a-button>
|
||||
<a-button type="primary" class="ml-16px" @click="onSubmit">确认</a-button>
|
||||
<Button @click="onClose">取消</Button>
|
||||
<Button type="primary" class="ml-16px" @click="onSubmit">确认</Button>
|
||||
</template>
|
||||
</a-modal>
|
||||
</Modal>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref, watch, nextTick } from 'vue';
|
||||
import { Button, Modal, Form, FormItem, Input, message } from 'ant-design-vue';
|
||||
import { postAccountGroups, putGroup } from '@/api/all/propertyMarketing';
|
||||
|
||||
const emits = defineEmits(['success', 'close']);
|
||||
@ -61,16 +63,14 @@ const open = (record = {}) => {
|
||||
};
|
||||
|
||||
async function onSubmit() {
|
||||
formRef.value.validate(async (errors) => {
|
||||
if (!errors) {
|
||||
const _fn = isEdit.value ? putGroup : postAccountGroups;
|
||||
const _params = isEdit.value ? { id: groupId.value, ...form.value } : form.value;
|
||||
const { code } = await _fn(_params);
|
||||
if (code === 200) {
|
||||
AMessage.success(isEdit.value ? '编辑成功' : '添加成功');
|
||||
emits('success');
|
||||
onClose();
|
||||
}
|
||||
formRef.value.validate().then(async () => {
|
||||
const _fn = isEdit.value ? putGroup : postAccountGroups;
|
||||
const _params = isEdit.value ? { id: groupId.value, ...form.value } : form.value;
|
||||
const { code } = await _fn(_params);
|
||||
if (code === 200) {
|
||||
message.success(isEdit.value ? '编辑成功' : '添加成功');
|
||||
emits('success');
|
||||
onClose();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@ -3,22 +3,28 @@
|
||||
* @Date: 2025-06-26 11:45:05
|
||||
-->
|
||||
<template>
|
||||
<a-modal v-model:visible="visible" title="删除分组" width="400px" modal-class="account-manage-modal" @close="onClose">
|
||||
<Modal
|
||||
v-model:open="visible"
|
||||
title="删除分组"
|
||||
centered
|
||||
width="400px"
|
||||
wrapClassName="account-manage-modal"
|
||||
@cancel="onClose"
|
||||
>
|
||||
<div class="flex items-center mb-24px">
|
||||
<img :src="icon1" width="20" height="20" class="mr-12px" />
|
||||
<span>确认删除 "{{ groupName }}" 这个分组吗?</span>
|
||||
</div>
|
||||
<template #footer>
|
||||
<a-button size="large" @click="onClose">取消</a-button>
|
||||
<a-button type="primary" class="ml-16px danger-btn" status="danger" size="large" @click="onDelete"
|
||||
>确认删除</a-button
|
||||
>
|
||||
<Button size="large" @click="onClose">取消</Button>
|
||||
<Button type="primary" class="ml-16px" danger size="large" @click="onDelete">确认删除</Button>
|
||||
</template>
|
||||
</a-modal>
|
||||
</Modal>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref } from 'vue';
|
||||
import { Button, Modal, message } from 'ant-design-vue';
|
||||
import { deleteGroup } from '@/api/all/propertyMarketing';
|
||||
import icon1 from '@/assets/img/media-account/icon-warn-1.png';
|
||||
|
||||
@ -46,7 +52,7 @@ const open = (record) => {
|
||||
async function onDelete() {
|
||||
const { code } = await deleteGroup(groupId.value);
|
||||
if (code === 200) {
|
||||
AMessage.success('删除成功');
|
||||
message.success('删除成功');
|
||||
emits('success');
|
||||
onClose();
|
||||
}
|
||||
|
||||
@ -3,84 +3,103 @@
|
||||
* @Date: 2025-06-25 17:51:46
|
||||
-->
|
||||
<template>
|
||||
<a-modal
|
||||
v-model:visible="visible"
|
||||
<Modal
|
||||
v-model:open="visible"
|
||||
width="900px"
|
||||
modal-class="account-manage-modal"
|
||||
:footer="false"
|
||||
wrapClassName="account-manage-modal"
|
||||
:footer="null"
|
||||
centered
|
||||
title="分组管理"
|
||||
:mask-closable="false"
|
||||
@close="close"
|
||||
:maskClosable="false"
|
||||
@cancel="close"
|
||||
>
|
||||
<div class="flex items-center justify-between mb-16px">
|
||||
<div class="filter-row-item flex items-center">
|
||||
<span class="s1 !color-#211F24 mr-12px">分组名称</span>
|
||||
<a-space size="medium" class="w-240px">
|
||||
<a-input v-model="query.name" placeholder="请搜索..." size="medium" allow-clear @change="reload">
|
||||
<Space size="medium" class="w-240px">
|
||||
<Input v-model:value="query.name" placeholder="请搜索..." size="middle" allowClear @change="reload">
|
||||
<template #prefix>
|
||||
<icon-search />
|
||||
</template>
|
||||
</a-input>
|
||||
</a-space>
|
||||
</Input>
|
||||
</Space>
|
||||
</div>
|
||||
<a-button type="primary" size="medium" @click="openAdd"
|
||||
<Button type="primary" size="middle" @click="openAdd"
|
||||
><template #icon>
|
||||
<icon-plus size="16" />
|
||||
<icon-plus size="16" class="mr-8px" />
|
||||
</template>
|
||||
<template #default>添加新分组</template>
|
||||
</a-button>
|
||||
</Button>
|
||||
</div>
|
||||
|
||||
<a-table
|
||||
column-resizable
|
||||
:columns="columns"
|
||||
:data="list"
|
||||
row-key="id"
|
||||
<Table
|
||||
:dataSource="list"
|
||||
rowKey="id"
|
||||
:loading="loading"
|
||||
:scroll="{ y: 500 }"
|
||||
class="h-500px"
|
||||
:pagination="false"
|
||||
@sorter-change="handleSorterChange"
|
||||
:showSorterTooltip="false"
|
||||
@change="
|
||||
(pagination, filters, sorter) => {
|
||||
if (sorter && sorter.columnKey) {
|
||||
handleSorterChange(sorter.columnKey, sorter.order);
|
||||
}
|
||||
}
|
||||
"
|
||||
>
|
||||
<template #empty>
|
||||
<Table.Column title="分组名称" dataIndex="name" />
|
||||
<Table.Column title="创建人" dataIndex="creator">
|
||||
<template #customRender="{ record }">
|
||||
{{ record.creator?.name || '-' }}
|
||||
</template>
|
||||
</Table.Column>
|
||||
<Table.Column title="创建日期" dataIndex="created_at" :width="160" key="created_at" :sorter="true">
|
||||
<template #customRender="{ record }">
|
||||
{{ exactFormatTime(record.created_at) }}
|
||||
</template>
|
||||
</Table.Column>
|
||||
<Table.Column title="操作" :align="'center'" :width="120">
|
||||
<template #customRender="{ record }">
|
||||
<div class="flex items-center">
|
||||
<img :src="icon1" width="16" height="16" class="mr-8px cursor-pointer" @click="openDelete(record)" />
|
||||
<Button type="primary" size="small" @click="openEdit(record)">编辑</Button>
|
||||
</div>
|
||||
</template>
|
||||
</Table.Column>
|
||||
<template #emptyText>
|
||||
<NoData>
|
||||
<span class="s1 mb-16px">暂无分组</span>
|
||||
<a-button type="primary" class="mb-16px" size="medium" @click="openAdd"
|
||||
<Button type="primary" class="mb-16px" size="middle" @click="openAdd"
|
||||
><template #icon>
|
||||
<icon-plus size="16"/>
|
||||
<icon-plus size="16" class="mr-8px" />
|
||||
</template>
|
||||
<template #default>去添加</template>
|
||||
</a-button>
|
||||
</Button>
|
||||
</NoData>
|
||||
</template>
|
||||
<template #action="{ record }">
|
||||
<div class="flex items-center">
|
||||
<img :src="icon1" width="16" height="16" class="mr-8px cursor-pointer" @click="openDelete(record)" />
|
||||
<a-button type="primary" @click="openEdit(record)">编辑</a-button>
|
||||
</div>
|
||||
</template>
|
||||
</a-table>
|
||||
</Table>
|
||||
<div v-if="pageInfo.total > 0" class="pagination-row flex justify-end">
|
||||
<a-pagination
|
||||
<Pagination
|
||||
:total="pageInfo.total"
|
||||
size="mini"
|
||||
show-total
|
||||
show-jumper
|
||||
show-page-size
|
||||
size="small"
|
||||
:showTotal="(total, range) => `共 ${total} 条`"
|
||||
showSizeChanger
|
||||
showQuickJumper
|
||||
:current="pageInfo.page"
|
||||
:page-size="pageInfo.pageSize"
|
||||
:pageSize="pageInfo.pageSize"
|
||||
@change="onPageChange"
|
||||
@page-size-change="onPageSizeChange"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<AddGroup ref="addGroupRef" @success="update" />
|
||||
<DeleteGroup ref="deleteGroupRef" @success="update" />
|
||||
</a-modal>
|
||||
</Modal>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref, reactive, onMounted } from 'vue';
|
||||
import { Button, Input, Modal, Space, Table, Pagination } from 'ant-design-vue';
|
||||
import { getAccountGroup } from '@/api/all/propertyMarketing';
|
||||
import { exactFormatTime } from '@/utils/tools';
|
||||
|
||||
@ -115,25 +134,6 @@ const loading = ref(false);
|
||||
const query = ref(cloneDeep(INITIAL_QUERY));
|
||||
const pageInfo = ref(cloneDeep(INITIAL_PAGE_INFO));
|
||||
|
||||
const columns = [
|
||||
{ title: '分组名称', dataIndex: 'name' },
|
||||
{
|
||||
title: '创建人',
|
||||
dataIndex: 'creator',
|
||||
render: ({ record }) => record.creator?.name || '-',
|
||||
},
|
||||
{
|
||||
title: '创建日期',
|
||||
dataIndex: 'created_at',
|
||||
width: 160,
|
||||
render: ({ record }) => exactFormatTime(record.created_at),
|
||||
sortable: {
|
||||
sortDirections: ['ascend', 'descend'],
|
||||
},
|
||||
},
|
||||
{ title: '操作', slotName: 'action', align: 'center', width: 120 },
|
||||
];
|
||||
|
||||
function open() {
|
||||
visible.value = true;
|
||||
getData();
|
||||
@ -188,8 +188,9 @@ const reload = () => {
|
||||
getData();
|
||||
};
|
||||
|
||||
const onPageChange = (current) => {
|
||||
const onPageChange = (current, pageSize) => {
|
||||
pageInfo.value.page = current;
|
||||
pageInfo.value.pageSize = pageSize;
|
||||
getData();
|
||||
};
|
||||
const onPageSizeChange = (pageSize) => {
|
||||
|
||||
@ -2,9 +2,9 @@
|
||||
|
||||
.account-manage-modal {
|
||||
border-radius: 8px;
|
||||
.arco-modal-body {
|
||||
.arco-btn {
|
||||
.arco-btn-icon {
|
||||
.ant-modal-body {
|
||||
.ant-btn {
|
||||
.ant-btn-icon {
|
||||
line-height: 16px;
|
||||
}
|
||||
}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user