shop-front-end/src/views/welcome/index.vue

1031 lines
31 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<script setup lang="ts">
import { Goods, Shop, Document, Money } from '@element-plus/icons-vue';
import { getStats, TodayLatestOrderGoodsDTO, TopGoodsDTO } from '@/api/shop/stats';
import { getShopListApi, ShopDTO, getModeText } from '@/api/shop/shop';
import { getBorrowReturnDynamicListApi, BorrowReturnDynamicDTO } from '@/api/shop/order';
import { markRaw, onMounted, ref } from 'vue';
import { useWxStore } from '@/store/modules/wx';
import { ElDialog, ElForm, ElFormItem, ElInput, ElMessage } from 'element-plus';
import { bindQyUserApi } from '@/api/ab98/user';
import qrcode from '@/assets/qrcode.png';
import { getBasicInfoByCorpidApi } from '@/api/qy/corp';
import { storeToRefs } from 'pinia';
defineOptions({
name: "Welcome"
});
const wxStore = useWxStore();
const { authCorpBasicInfo } = storeToRefs(wxStore);
const shopList = ref<ShopDTO[]>([]);
const currentShop = ref<ShopDTO | null>(null);
const selectedShopId = ref<number | null>(null);
const shopData = ref<{
name: string;
icon: any; // 假设这里是 Element Plus 的图标组件
value: number;
}[]>([
]);
const unReturnedData = ref([
{ name: '未还商品', value: 0 },
{ name: '未还订单', value: 0 },
{ name: '未还金额', value: 0 }
]);
const deviceData = ref([
{ name: '总柜子', value: 0 },
{ name: '总格口', value: 0 },
{ name: '已关联', value: 0 },
{ name: '未关联', value: 0 },
{ name: '网关', value: 0 }
]);
const topGoods = ref<TopGoodsDTO[]>([]);
const todayLatestOrderGoods = ref<TodayLatestOrderGoodsDTO[]>([]);
const maxOccurrenceCount = ref(0);
// 借还动态数据
const borrowReturnDynamicList = ref<BorrowReturnDynamicDTO[]>([]);
const loading = ref(false);
const showDialog = ref(false);
const form = ref({ name: '', idCard: '' });
const rules = {
name: [{ required: true, message: '请输入姓名', trigger: 'blur' }],
idCard: [
{ required: true, message: '请输入身份证号', trigger: 'blur' },
{ pattern: /^\d{17}[\dXx]$/, message: '身份证格式不正确', trigger: 'blur' }
]
};
const handleSubmit = async () => {
try {
const { data } = await bindQyUserApi({
qyUserId: wxStore.qyUser?.id,
name: form.value.name,
idNum: form.value.idCard
});
ElMessage.success('绑定成功');
showDialog.value = false;
} catch (error) {
ElMessage.error(error.message || '绑定失败');
}
};
const handleShopChange = (shopId: number) => {
const selectedShop = shopList.value.find(shop => shop.shopId === shopId);
if (selectedShop) {
currentShop.value = selectedShop;
// 重新获取选中商店的统计数据
fetchShopStats();
}
};
const fetchShopStats = async () => {
if (!currentShop.value) return;
try {
const { data } = await getStats(wxStore.corpid);
shopData.value = [
{ name: '商店', icon: markRaw(Shop), value: data.shopCount },
{ name: '商品总数量', icon: markRaw(Goods), value: data.goodsCount },
{ name: '商品总订单', icon: markRaw(Document), value: data.orderCount },
{ name: '商品总金额', icon: markRaw(Money), value: data.goodsTotalAmount }
];
unReturnedData.value = [
{ name: '未还商品', value: data.unReturnedGoodsCount },
{ name: '未还订单', value: data.unReturnedOrderCount },
{ name: '未还金额', value: data.unReturnedAmount }
];
deviceData.value = [
{ name: '总柜子', value: data.cabinetCount },
{ name: '总格口', value: data.cellCount },
{ name: '已关联', value: data.linkedCellCount },
{ name: '未关联', value: data.unmanagedCellCount },
{ name: '网关', value: data.gatewayCount }
];
topGoods.value = data.topGoods;
todayLatestOrderGoods.value = data.todayLatestOrderGoods;
maxOccurrenceCount.value = Math.max(...data.topGoods.map(item => item.occurrenceCount), 1);
} catch (error) {
console.error('获取统计数据失败:', error);
}
};
const fetchShopList = async () => {
try {
const { data } = await getShopListApi({ corpid: wxStore.corpid });
shopList.value = data;
if (data.length > 0) {
currentShop.value = data[0];
selectedShopId.value = data[0].shopId;
}
} catch (error) {
console.error('获取商店列表失败:', error);
}
};
const fetchCorpBasicInfo = async () => {
try {
const { data } = await getBasicInfoByCorpidApi(wxStore.corpid);
if (data) {
// 更新企业基本信息
wxStore.setAuthCorpBasicInfo(data);
}
} catch (error) {
console.error('获取企业基本信息失败:', error);
ElMessage.error('获取企业基本信息失败');
}
};
// 获取借还动态数据
const fetchBorrowReturnDynamic = async () => {
loading.value = true;
try {
const { data } = await getBorrowReturnDynamicListApi({
pageNum: 1,
pageSize: 20
});
if (data && data.rows) {
borrowReturnDynamicList.value = data.rows;
}
} catch (error) {
console.error('获取借还动态失败:', error);
ElMessage.error('获取借还动态失败');
} finally {
loading.value = false;
}
};
// 格式化时间显示
const formatTime = (time: Date | string) => {
if (!time) return '';
const date = new Date(time);
return date.toLocaleString('zh-CN', {
month: '2-digit',
day: '2-digit',
hour: '2-digit',
minute: '2-digit'
});
};
// 获取动态类型图标
const getDynamicTypeIcon = (dynamicType: number) => {
return dynamicType === 0 ? 'el-icon-shopping-bag-1' : 'el-icon-refresh';
};
// 获取动态类型颜色
const getDynamicTypeColor = (dynamicType: number) => {
return dynamicType === 0 ? '#409EFF' : '#67C23A';
};
// 获取状态颜色
const getStatusColor = (status?: number) => {
if (status === undefined) return '#909399';
switch (status) {
case 0: return '#909399'; // 未退还
case 1: return '#E6A23C'; // 待审批
case 2: return '#67C23A'; // 已通过
case 3: return '#F56C6C'; // 已驳回
case 4: return '#409EFF'; // 开柜中
default: return '#909399';
}
};
// 处理图片字符串将逗号分隔的图片URL转换为数组
const parseImages = (images?: string): string[] => {
if (!images) return [];
return images.split(',').map(img => img.trim()).filter(img => img.length > 0);
};
onMounted(async () => {
await fetchShopList();
// 获取企业基本信息
await fetchCorpBasicInfo();
try {
const { data } = await getStats(wxStore.corpid);
shopData.value = [
{ name: '商店', icon: markRaw(Shop), value: data.shopCount },
{ name: '商品总数量', icon: markRaw(Goods), value: data.goodsCount },
{ name: '商品总订单', icon: markRaw(Document), value: data.orderCount },
{ name: '商品总金额', icon: markRaw(Money), value: data.goodsTotalAmount }
];
unReturnedData.value = [
{ name: '未还商品', value: data.unReturnedGoodsCount },
{ name: '未还订单', value: data.unReturnedOrderCount },
{ name: '未还金额', value: data.unReturnedAmount }
];
deviceData.value = [
{ name: '总柜子', value: data.cabinetCount },
{ name: '总格口', value: data.cellCount },
{ name: '已关联', value: data.linkedCellCount },
{ name: '未关联', value: data.unmanagedCellCount },
{ name: '网关', value: data.gatewayCount }
];
topGoods.value = data.topGoods;
todayLatestOrderGoods.value = data.todayLatestOrderGoods;
maxOccurrenceCount.value = Math.max(...data.topGoods.map(item => item.occurrenceCount), 1);
} catch (error) {
console.error('获取统计数据失败:', error);
}
// 获取借还动态数据
await fetchBorrowReturnDynamic();
if (wxStore.qyUser && !wxStore.qyUser.ab98UserId) {
showDialog.value = true;
}
});
</script>
<template>
<div class="welcome-container">
<el-row :gutter="12">
<el-col :span="17">
<!-- 商店选择容器 -->
<div class="section-container shop-selection-container" v-if="currentShop">
<div class="section-title">
<div class="title-bar"></div>
<div class="title-text">商家信息</div>
</div>
<div class="shop-content">
<div class="shop-info">
<el-image :src="currentShop.coverImg || '/src/assets/login/login-bg.png'" fit="cover"
class="shop-image" />
<div class="shop-details">
<div class="shop-name-container">
<h3 class="shop-name">{{ authCorpBasicInfo?.corpName || '' }}</h3>
<!-- <el-select
v-model="selectedShopId"
placeholder="选择商店"
class="shop-selector"
@change="handleShopChange"
>
<el-option
v-for="shop in shopList"
:key="shop.shopId"
:label="shop.shopName"
:value="shop.shopId"
/>
</el-select> -->
</div>
<!-- <p class="shop-mode">{{ getModeText(currentShop.mode) }}</p> -->
</div>
</div>
<div class="shop-qrcode">
<el-image :src="qrcode" fit="contain" class="qrcode-image" />
<p class="qrcode-text">扫码进入小程序</p>
</div>
</div>
</div>
<!-- 待办事项 -->
<div class="section-container todo-container">
<div class="section-title">
<div class="title-bar"></div>
<div class="title-text">数据统计</div>
</div>
<el-row :gutter="12" class="todo-section">
<el-col :span="6" v-for="item in shopData" :key="item.name">
<el-card shadow="never" class="todo-card">
<div class="todo-content">
<el-icon :size="30" class="todo-icon">
<component :is="item.icon" />
</el-icon>
<div class="todo-count">{{ item.value }}</div>
<div class="todo-name">{{ item.name }}</div>
</div>
</el-card>
</el-col>
</el-row>
</div>
<el-row :gutter="12">
<el-col :span="12">
<div class="section-container shop-container">
<div class="section-title">
<div class="title-bar"></div>
<div class="title-text">未还统计</div>
</div>
<el-row :gutter="12" class="data-section">
<!-- 商店数据 -->
<el-col :span="8" v-for="item in unReturnedData" :key="item.name">
<el-card shadow="never" :body-style="{ padding: ' 20px 0' }" class="todo-card">
<div class="todo-content">
<div class="todo-count">{{ item.value }}</div>
<div class="todo-name">{{ item.name }}</div>
</div>
</el-card>
</el-col>
</el-row>
</div>
</el-col>
<!-- 智能设备 -->
<el-col :span="12">
<div class="section-container device-container">
<div class="section-title">
<div class="title-bar"></div>
<div class="title-text">智能设备</div>
</div>
<el-row :gutter="12" class="data-section">
<el-col :span="4" v-for="item in deviceData" :key="item.name">
<el-card shadow="never" :body-style="{ padding: ' 20px 0' }" class="todo-card">
<div class="todo-content">
<div class="todo-count">{{ item.value }}</div>
<div class="todo-name">{{ item.name }}</div>
</div>
</el-card>
</el-col>
</el-row>
</div>
</el-col>
</el-row>
<!-- 商品信息 -->
<el-row :gutter="12">
<!-- 今日最新订单 -->
<!--
<el-col :span="12">
<div class="section-container order-container">
<div class="section-title">
<div class="title-bar"></div>
<div class="title-text">今日数据</div>
</div>
<div class="goods-list">
<el-card shadow="never" class="goods-item" v-for="item in todayLatestOrderGoods"
:key="item.orderGoodsId" :body-style="{ padding: '0' }">
<div class="goods-item-content">
<div class="goods-left">
<el-image :src="item.coverImg" fit="contain" class="goods-image" />
<div class="goods-name">{{ item.goodsName }}</div>
</div>
<div class="goods-right">
<div class="goods-count">数量:{{ item.quantity }}</div>
<div class="goods-count">{{ item.totalAmount }}元</div>
<div class="goods-count buyer-name">{{ item.buyerName }}</div>
<div class="goods-count">{{ item.createTimeStr }}</div>
</div>
</div>
</el-card>
</div>
</div>
</el-col>
-->
</el-row>
</el-col>
<!-- 热门商品 -->
<!-- <el-col :span="7">
<div class="section-container goods-container">
<div class="section-title">
<div class="title-bar"></div>
<div class="title-text">借还排行</div>
</div>
<div class="goods-list">
<el-card shadow="never" class="goods-item" v-for="item in topGoods" :key="item.goodsId"
:body-style="{ padding: '0' }">
<div class="goods-item-content">
<div class="goods-left">
<el-image :src="item.coverImg" fit="contain" class="goods-image" />
<div class="goods-name">{{ item.goodsName }}</div>
</div>
<div class="goods-right">
<el-progress :percentage="(item.occurrenceCount / maxOccurrenceCount) * 100" :show-text="false"
:stroke-width="12" class="goods-progress" />
<div class="goods-count">{{ item.occurrenceCount }}次</div>
</div>
</div>
</el-card>
</div>
</div>
</el-col> -->
<!-- 借还动态 -->
<el-col :span="7">
<div class="section-container dynamic-container">
<div class="section-title">
<div class="title-bar"></div>
<div class="title-text">借还动态</div>
</div>
<div class="dynamic-content">
<el-timeline v-if="borrowReturnDynamicList.length > 0" class="dynamic-timeline">
<el-timeline-item v-for="item in borrowReturnDynamicList"
:key="`${item.orderGoodsId}-${item.dynamicType}`"
:timestamp="formatTime(item.dynamicType === 0 ? item.orderTime : item.operateTime)" placement="top"
:color="getDynamicTypeColor(item.dynamicType)">
<el-card shadow="hover" class="dynamic-card">
<div class="dynamic-card-content">
<div class="dynamic-header">
<el-icon :color="getDynamicTypeColor(item.dynamicType)" class="dynamic-icon">
<component :is="getDynamicTypeIcon(item.dynamicType)" />
</el-icon>
<span class="dynamic-type" :style="{ color: getDynamicTypeColor(item.dynamicType) }">
{{ item.dynamicTypeStr }}
</span>
<el-tag v-if="item.dynamicType === 1 && item.status !== undefined"
:color="getStatusColor(item.status)" size="small" class="status-tag">
{{ item.statusStr }}
</el-tag>
</div>
<div class="dynamic-info">
<!-- 商品图片和基本信息 -->
<div class="goods-info">
<el-image v-if="item.coverImg" :src="item.coverImg" fit="cover" class="goods-image"
:preview-src-list="[item.coverImg]" preview-teleported>
<template #error>
<div class="image-error">图片加载失败</div>
</template>
</el-image>
<div class="goods-details">
<span class="goods-name">{{ item.goodsName }}</span>
<span class="goods-price">¥{{ item.goodsPrice }}</span>
<div class="user-info">
<span class="user-name">{{ item.orderName }}</span>
<span class="user-mobile">{{ item.orderMobile }}</span>
</div>
<div class="location-info">
<span class="cabinet-name">{{ item.cabinetName }}</span>
<span class="cell-no">格口{{ item.cellNo }}</span>
</div>
</div>
</div>
<div v-if="item.dynamicType === 1" class="approval-info">
<!-- 图片区域 - 归还图片和审核图片放在同一行 -->
<div class="images-row" v-if="item.images || item.auditImages">
<!-- 归还图片 -->
<div v-if="item.images" class="images-section">
<div class="images-label">归还图片:</div>
<div class="images-list">
<el-image v-for="(img, index) in parseImages(item.images)" :key="index" :src="img"
fit="cover" class="return-image" :preview-src-list="parseImages(item.images)"
preview-teleported>
<template #error>
<div class="image-error">图片加载失败</div>
</template>
</el-image>
</div>
</div>
<!-- 审核图片 -->
<div v-if="item.auditImages" class="images-section">
<div class="images-label">审核图片:</div>
<div class="images-list">
<el-image v-for="(img, index) in parseImages(item.auditImages)" :key="index" :src="img"
fit="cover" class="audit-image" :preview-src-list="parseImages(item.auditImages)"
preview-teleported>
<template #error>
<div class="image-error">图片加载失败</div>
</template>
</el-image>
</div>
</div>
</div>
<div v-if="item.auditName" class="audit-info">
<span class="audit-label">审批人:</span>
<span class="audit-name">{{ item.auditName }}</span>
</div>
<div v-if="item.auditRemark && item.auditRemark != '自动审批'" class="remark-info">
<span class="remark-label">说明:</span>
<span class="audit-remark">{{ item.auditRemark }}</span>
</div>
</div>
</div>
</div>
</el-card>
</el-timeline-item>
</el-timeline>
<div v-else-if="loading" class="dynamic-empty">
<el-skeleton :rows="5" animated />
</div>
<div v-else class="dynamic-empty">
<el-empty description="暂无借还动态" />
</div>
</div>
</div>
</el-col>
</el-row>
<el-dialog v-model="showDialog" title="请绑定汇邦云账号" :close-on-click-modal="false" width="30%">
<el-form :model="form" :rules="rules" label-width="80px">
<el-form-item label="姓名" prop="name">
<el-input v-model="form.name" />
</el-form-item>
<el-form-item label="身份证号" prop="idCard">
<el-input v-model="form.idCard" maxlength="18" show-word-limit />
</el-form-item>
</el-form>
<template #footer>
<el-button type="primary" @click="handleSubmit">提交</el-button>
</template>
</el-dialog>
</div>
</template>
<style scoped lang="scss">
:deep(.el-card) {
border: none; // 移除卡片边框;
}
.welcome-container {
.section-title {
display: flex;
align-items: center;
margin-bottom: 5px;
.title-bar {
width: 3px;
height: 16px;
background-color: var(--el-color-primary);
margin-right: 8px;
border-radius: 2px;
}
.title-text {
font-size: 16px;
font-weight: bold;
color: var(--el-text-color-primary);
}
}
.section-container {
margin-bottom: 12px;
padding: 15px;
background-color: #fff;
border-radius: 4px;
box-shadow: 0 1px 4px rgba(0, 0, 0, 0.1);
}
.todo-section {
margin-bottom: 0;
.todo-card {
height: 100%;
border: none;
.todo-content {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
padding: 10px 0;
.todo-icon {
margin-bottom: 10px;
color: var(--el-color-primary);
}
}
}
}
.todo-count {
font-size: 24px;
font-weight: bold;
margin-bottom: 5px;
text-align: center;
}
.todo-name {
font-size: 14px;
color: var(--el-text-color-secondary);
text-align: center;
}
.data-section {
margin-bottom: 0;
}
.goods-card,
.order-card {
height: 100%;
border: none;
.goods-image,
.order-image {
width: 100%;
height: 140px;
border-radius: 4px 4px 0 0;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
}
.goods-content,
.order-content {
padding: 10px;
.goods-name,
.order-name {
font-size: 14px;
font-weight: bold;
margin-bottom: 5px;
text-align: center;
}
.goods-count,
.order-info {
font-size: 12px;
color: var(--el-text-color-secondary);
text-align: center;
}
}
}
.goods-list {
.goods-item {
border: none;
.goods-item-content {
display: flex;
align-items: center;
justify-content: space-between;
padding: 3px;
.goods-left {
display: flex;
align-items: center;
flex: 1;
.goods-image {
width: 100px;
height: 80px;
border-radius: 4px;
margin-right: 12px;
/* box-shadow: 0 2px 6px rgba(0, 0, 0, 0.1); */
}
.goods-name {
font-size: 14px;
font-weight: bold;
}
}
.goods-right {
display: flex;
align-items: center;
.goods-progress {
flex: 1;
margin-right: 2px;
}
.goods-count {
text-align: right;
font-size: 14px;
color: var(--el-text-color-primary);
}
.buyer-name {
padding-left: 10px;
flex-grow: 1;
text-align: left;
}
}
}
}
}
.goods-container {
margin-bottom: 0;
.goods-right {
width: 150px;
}
.goods-count {
width: 45px;
}
}
.order-container {
margin-bottom: 0;
.goods-right {
width: 250px;
}
.goods-count {
width: 60px;
}
}
.shop-selection-container {
padding: 20px;
margin-bottom: 12px;
.shop-content {
display: flex;
justify-content: space-between;
align-items: center;
}
.shop-info {
display: flex;
align-items: flex-start;
flex: 1;
.shop-image {
width: 240px;
height: 160px;
border-radius: 8px;
margin-left: 16px;
margin-right: 26px;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
}
.shop-details {
padding-top: 16px;
.shop-name-container {
display: flex;
align-items: center;
gap: 12px;
margin-bottom: 8px;
.shop-name {
font-size: 20px;
font-weight: bold;
color: var(--el-text-color-primary);
margin: 0;
white-space: nowrap;
}
.shop-selector {
min-width: 200px;
:deep(.el-input__wrapper) {
border-radius: 4px;
border: 1px solid var(--el-border-color);
box-shadow: none;
&:hover {
border-color: var(--el-color-primary);
}
&.is-focus {
border-color: var(--el-color-primary);
box-shadow: 0 0 0 1px var(--el-color-primary);
}
}
}
}
.shop-mode {
font-size: 14px;
color: var(--el-text-color-secondary);
margin: 0;
}
}
}
.shop-qrcode {
display: flex;
flex-direction: column;
align-items: center;
margin-right: 20px;
.qrcode-image {
width: 160px;
height: 160px;
border-radius: 4px;
margin-bottom: 8px;
}
.qrcode-text {
font-size: 14px;
font-weight: bold;
color: var(--el-text-color-secondary);
margin: 0;
text-align: center;
}
}
}
// 借还动态样式
.dynamic-container {
margin-bottom: 0;
height: 88vh;
overflow-y: auto;
.dynamic-content {
.dynamic-timeline {
padding: 0;
:deep(.el-timeline-item) {
.el-timeline-item__timestamp {
font-size: 12px;
color: var(--el-text-color-secondary);
margin-bottom: 8px;
}
.el-timeline-item__node {
width: 12px;
height: 12px;
}
}
}
.dynamic-card {
margin-bottom: 12px;
border: 1px solid var(--el-border-color);
.dynamic-card-content {
.dynamic-header {
display: flex;
align-items: center;
margin-bottom: 8px;
padding-bottom: 8px;
border-bottom: 1px solid var(--el-border-color-light);
.dynamic-icon {
font-size: 16px;
margin-right: 8px;
}
.dynamic-type {
font-size: 14px;
font-weight: bold;
margin-right: 8px;
}
.status-tag {
margin-left: auto;
color: white;
border: none;
}
}
.dynamic-info {
.goods-info {
display: flex;
align-items: flex-start;
margin-bottom: 8px;
.goods-image {
width: 120px;
height: 90px;
border-radius: 4px;
margin-right: 12px;
flex-shrink: 0;
cursor: pointer;
border: 1px solid var(--el-border-color-light);
}
.goods-details {
flex: 1;
display: flex;
flex-direction: column;
justify-content: space-between;
min-height: 60px;
.goods-name {
font-size: 14px;
font-weight: bold;
color: var(--el-text-color-primary);
margin-bottom: 4px;
line-height: 1.4;
display: -webkit-box;
-webkit-line-clamp: 2;
-webkit-box-orient: vertical;
overflow: hidden;
}
.goods-price {
font-size: 14px;
color: var(--el-color-primary);
font-weight: bold;
align-self: flex-start;
margin-bottom: 6px;
}
.user-info {
display: flex;
justify-content: space-between;
margin-bottom: 4px;
.user-name,
.user-mobile {
font-size: 12px;
color: var(--el-text-color-secondary);
}
}
.location-info {
display: flex;
justify-content: space-between;
.cabinet-name,
.cell-no {
font-size: 12px;
color: var(--el-text-color-secondary);
}
}
}
}
.user-info,
.location-info {
display: none;
}
.approval-info {
background-color: var(--el-fill-color-light);
border-radius: 4px;
padding: 12px;
margin-top: 8px;
.images-row {
display: flex;
gap: 20px;
margin-bottom: 12px;
flex-wrap: wrap;
}
.images-section {
flex: 1;
min-width: 0;
.images-label {
font-size: 12px;
font-weight: bold;
color: var(--el-text-color-secondary);
margin-bottom: 6px;
}
.images-list {
display: flex;
flex-wrap: wrap;
gap: 6px;
.return-image,
.audit-image {
width: 110px;
height: 70px;
border-radius: 4px;
cursor: pointer;
border: 1px solid var(--el-border-color-light);
flex-shrink: 0;
}
}
}
.audit-info,
.remark-info {
font-size: 12px;
color: var(--el-text-color-secondary);
.audit-label,
.remark-label {
font-weight: bold;
}
.audit-name,
.audit-remark {
color: var(--el-text-color-primary);
}
}
.remark-info {
margin-top: 4px;
}
}
}
}
}
.image-error {
width: 100%;
height: 100%;
display: flex;
align-items: center;
justify-content: center;
background-color: var(--el-fill-color-light);
color: var(--el-text-color-secondary);
font-size: 12px;
border-radius: 4px;
}
.dynamic-empty {
text-align: center;
padding: 40px 0;
:deep(.el-empty) {
.el-empty__description {
font-size: 14px;
color: var(--el-text-color-secondary);
}
}
}
}
}
}
</style>