feat(amazon):重构亚马逊仪表板组件并新增商标筛查功能
- 将原有复杂逻辑拆分为独立组件:AsinQueryPanel、GenmaiSpiritPanel、TrademarkCheckPanel - 新增商标批量筛查功能,支持商标状态、类别、权利人等信息查询 - 优化UI布局,改进标签页样式和响应式设计 - 重构数据处理逻辑,使用计算属性优化性能- 完善分页功能,支持不同tab的数据展示 - 移除冗余代码,提高组件可维护性 - 添加跟卖精灵功能说明和注意事项展示-优化空状态和加载状态的用户体验
This commit is contained in:
@@ -0,0 +1,575 @@
|
||||
<script setup lang="ts">
|
||||
import { ref, inject, defineAsyncComponent } from 'vue'
|
||||
import { ElMessage } from 'element-plus'
|
||||
import { handlePlatformFileExport } from '../../utils/settings'
|
||||
import { getUsernameFromToken } from '../../utils/token'
|
||||
const TrialExpiredDialog = defineAsyncComponent(() => import('../common/TrialExpiredDialog.vue'))
|
||||
|
||||
const refreshVipStatus = inject<() => Promise<boolean>>('refreshVipStatus')
|
||||
|
||||
const props = defineProps<{
|
||||
isVip: boolean
|
||||
}>()
|
||||
|
||||
const emit = defineEmits<{
|
||||
updateData: [data: any[]]
|
||||
}>()
|
||||
|
||||
const trademarkData = ref<any[]>([])
|
||||
const trademarkFileName = ref('')
|
||||
const trademarkUpload = ref<HTMLInputElement | null>(null)
|
||||
const trademarkLoading = ref(false)
|
||||
const trademarkProgress = ref(0)
|
||||
const exportLoading = ref(false)
|
||||
const currentStep = ref(0)
|
||||
const totalSteps = ref(0)
|
||||
|
||||
// 查询状态: idle-待开始, inProgress-进行中, done-已完成, error-错误, networkError-网络错误, cancel-已取消
|
||||
const queryStatus = ref<'idle' | 'inProgress' | 'done' | 'error' | 'networkError' | 'cancel'>('idle')
|
||||
const errorMessage = ref('')
|
||||
const statusConfig = {
|
||||
idle: {
|
||||
icon: '/image/img.png',
|
||||
title: '暂无数据,请按左侧流程操作',
|
||||
desc: ''
|
||||
},
|
||||
inProgress: {
|
||||
icon: '/icon/wait.png',
|
||||
title: '正在查询中...',
|
||||
desc: '请耐心等待,正在为您筛查商标信息'
|
||||
},
|
||||
done: {
|
||||
icon: '/icon/done.png',
|
||||
title: '筛查完成',
|
||||
desc: '已成功完成所有商标筛查任务'
|
||||
},
|
||||
error: {
|
||||
icon: '/icon/error.png',
|
||||
title: '查询失败',
|
||||
desc: '查询过程中出现错误,请重试'
|
||||
},
|
||||
networkError: {
|
||||
icon: '/icon/networkErrors.png',
|
||||
title: '网络连接失败',
|
||||
desc: '网络异常,请检查网络连接后重试'
|
||||
},
|
||||
cancel: {
|
||||
icon: '/icon/cancel.png',
|
||||
title: '已取消查询',
|
||||
desc: '您已取消本次查询任务'
|
||||
}
|
||||
}
|
||||
|
||||
// 选择的账号(模拟数据)
|
||||
const selectedAccount = ref('chensri3.com')
|
||||
const accountOptions = [
|
||||
{ label: 'chensri3.com', value: 'chensri3.com', status: '美国' },
|
||||
{ label: 'zhangikcpi.com', value: 'zhangikcpi.com', status: '加拿大' },
|
||||
{ label: 'hhhhsoutlook...', value: 'hhhhsoutlook', status: '日本' }
|
||||
]
|
||||
|
||||
// 地区选择
|
||||
const region = ref('美国')
|
||||
const regionOptions = [
|
||||
{ label: '美国', value: '美国', flag: '🇺🇸' },
|
||||
{ label: '日本', value: '日本', flag: '🇯🇵' },
|
||||
{ label: '加拿大', value: '加拿大', flag: '🇨🇦' }
|
||||
]
|
||||
|
||||
// 查询类型多选
|
||||
const queryTypes = ref<string[]>(['product'])
|
||||
|
||||
const showTrialExpiredDialog = ref(false)
|
||||
const trialExpiredType = ref<'device' | 'account' | 'both' | 'subscribe'>('account')
|
||||
const vipStatus = inject<any>('vipStatus')
|
||||
|
||||
function showMessage(message: string, type: 'success' | 'warning' | 'error' | 'info' = 'info') {
|
||||
ElMessage({ message, type })
|
||||
}
|
||||
|
||||
function openTrademarkUpload() {
|
||||
trademarkUpload.value?.click()
|
||||
}
|
||||
|
||||
async function handleTrademarkUpload(e: Event) {
|
||||
const input = e.target as HTMLInputElement
|
||||
const file = input.files?.[0]
|
||||
if (!file) return
|
||||
|
||||
const ok = /\.xlsx?$/.test(file.name)
|
||||
if (!ok) {
|
||||
showMessage('仅支持 .xlsx/.xls 文件', 'warning')
|
||||
return
|
||||
}
|
||||
|
||||
trademarkFileName.value = file.name
|
||||
queryStatus.value = 'idle' // 重置状态
|
||||
trademarkData.value = []
|
||||
emit('updateData', [])
|
||||
showMessage(`文件已准备:${file.name}`, 'success')
|
||||
input.value = ''
|
||||
}
|
||||
|
||||
async function startTrademarkQuery() {
|
||||
if (!trademarkFileName.value) {
|
||||
showMessage('请先导入商标列表', 'warning')
|
||||
return
|
||||
}
|
||||
|
||||
if (refreshVipStatus) await refreshVipStatus()
|
||||
|
||||
if (!props.isVip) {
|
||||
if (vipStatus) trialExpiredType.value = vipStatus.value.expiredType
|
||||
showTrialExpiredDialog.value = true
|
||||
return
|
||||
}
|
||||
|
||||
trademarkLoading.value = true
|
||||
trademarkProgress.value = 0
|
||||
trademarkData.value = []
|
||||
queryStatus.value = 'inProgress'
|
||||
|
||||
const mockData = [
|
||||
{ name: 'SONY', status: '已注册', class: '9类-电子产品', owner: 'Sony Corporation', expireDate: '2028-12-31', similarity: 0 },
|
||||
{ name: 'SUMSUNG', status: '近似风险', class: '9类-电子产品', owner: '待查询', expireDate: '-', similarity: 85 },
|
||||
{ name: 'NIKE', status: '已注册', class: '25类-服装鞋帽', owner: 'Nike, Inc.', expireDate: '2029-06-15', similarity: 0 },
|
||||
{ name: 'ADIBAS', status: '近似风险', class: '25类-服装鞋帽', owner: '待查询', expireDate: '-', similarity: 92 },
|
||||
{ name: 'MyBrand', status: '可注册', class: '未查询', owner: '-', expireDate: '-', similarity: 0 }
|
||||
]
|
||||
|
||||
totalSteps.value = mockData.length
|
||||
|
||||
try {
|
||||
for (let i = 0; i < mockData.length; i++) {
|
||||
if (!trademarkLoading.value) break // 被取消
|
||||
|
||||
currentStep.value = i + 1
|
||||
await new Promise(resolve => setTimeout(resolve, 800))
|
||||
trademarkData.value.push(mockData[i])
|
||||
trademarkProgress.value = Math.round(((i + 1) / mockData.length) * 100)
|
||||
}
|
||||
|
||||
if (trademarkLoading.value) {
|
||||
queryStatus.value = 'done'
|
||||
emit('updateData', trademarkData.value)
|
||||
showMessage('商标筛查完成', 'success')
|
||||
}
|
||||
} catch (error: any) {
|
||||
if (error.message && error.message.includes('网络')) {
|
||||
queryStatus.value = 'networkError'
|
||||
errorMessage.value = '网络连接失败'
|
||||
} else {
|
||||
queryStatus.value = 'error'
|
||||
errorMessage.value = error.message || '查询失败'
|
||||
}
|
||||
showMessage(errorMessage.value, 'error')
|
||||
} finally {
|
||||
trademarkLoading.value = false
|
||||
currentStep.value = 0
|
||||
totalSteps.value = 0
|
||||
}
|
||||
}
|
||||
|
||||
function stopTrademarkQuery() {
|
||||
trademarkLoading.value = false
|
||||
queryStatus.value = 'cancel'
|
||||
currentStep.value = 0
|
||||
totalSteps.value = 0
|
||||
showMessage('已停止筛查', 'info')
|
||||
}
|
||||
|
||||
async function exportTrademarkData() {
|
||||
if (!trademarkData.value.length) {
|
||||
showMessage('没有数据可供导出', 'warning')
|
||||
return
|
||||
}
|
||||
|
||||
exportLoading.value = true
|
||||
|
||||
let html = `<table>
|
||||
<tr><th>商标名称</th><th>状态</th><th>类别</th><th>权利人</th><th>到期日期</th><th>相似度</th></tr>`
|
||||
|
||||
trademarkData.value.forEach(item => {
|
||||
html += `<tr>
|
||||
<td>${item.name || ''}</td>
|
||||
<td>${item.status || ''}</td>
|
||||
<td>${item.class || ''}</td>
|
||||
<td>${item.owner || ''}</td>
|
||||
<td>${item.expireDate || ''}</td>
|
||||
<td>${item.similarity ? item.similarity + '%' : '-'}</td>
|
||||
</tr>`
|
||||
})
|
||||
html += '</table>'
|
||||
|
||||
const blob = new Blob([html], { type: 'application/vnd.ms-excel' })
|
||||
const fileName = `商标筛查结果_${new Date().toISOString().slice(0, 10)}.xls`
|
||||
|
||||
const username = getUsernameFromToken()
|
||||
const success = await handlePlatformFileExport('amazon', blob, fileName, username)
|
||||
|
||||
if (success) {
|
||||
showMessage('Excel文件导出成功!', 'success')
|
||||
}
|
||||
exportLoading.value = false
|
||||
}
|
||||
|
||||
function toggleQueryType(type: string) {
|
||||
const index = queryTypes.value.indexOf(type)
|
||||
if (index > -1) {
|
||||
queryTypes.value.splice(index, 1)
|
||||
} else {
|
||||
queryTypes.value.push(type)
|
||||
}
|
||||
}
|
||||
|
||||
function viewTrademarkExample() {
|
||||
showMessage('商标列表应包含一列商标名称', 'info')
|
||||
}
|
||||
|
||||
function downloadTrademarkTemplate() {
|
||||
const html = '<table><tr><th>商标名称</th></tr><tr><td>SONY</td></tr><tr><td>NIKE</td></tr><tr><td>MyBrand</td></tr></table>'
|
||||
const blob = new Blob([html], { type: 'application/vnd.ms-excel' })
|
||||
const url = URL.createObjectURL(blob)
|
||||
const a = document.createElement('a')
|
||||
a.href = url
|
||||
a.download = '商标列表模板.xls'
|
||||
document.body.appendChild(a)
|
||||
a.click()
|
||||
document.body.removeChild(a)
|
||||
URL.revokeObjectURL(url)
|
||||
}
|
||||
|
||||
defineExpose({
|
||||
trademarkLoading,
|
||||
trademarkProgress,
|
||||
trademarkData,
|
||||
queryStatus,
|
||||
statusConfig
|
||||
})
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="trademark-panel">
|
||||
<div class="steps-flow">
|
||||
<!-- 1. 导入签署精灵账品批格 -->
|
||||
<div class="flow-item">
|
||||
<div class="step-index">1</div>
|
||||
<div class="step-card">
|
||||
<div class="step-header"><div class="title">导入“卖家精灵选品表格”</div></div>
|
||||
<div class="desc">在卖家精灵导出文档时,必须要勾选“导出主图”,具体操作请<span class="link" @click.prevent="viewTrademarkExample">点击查看</span></div>
|
||||
<div class="dropzone" @click="openTrademarkUpload">
|
||||
<div class="dz-icon">📤</div>
|
||||
<div class="dz-text">点击或将文件拖拽到这里上传</div>
|
||||
<div class="dz-sub">支持 .xls .xlsx</div>
|
||||
</div>
|
||||
<input ref="trademarkUpload" style="display:none" type="file" accept=".xls,.xlsx" @change="handleTrademarkUpload" :disabled="trademarkLoading" />
|
||||
|
||||
<div v-if="trademarkFileName" class="file-chip">
|
||||
<span class="dot"></span>
|
||||
<span class="name">{{ trademarkFileName }}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 2. 选择亚马逊商标地区 -->
|
||||
<div class="flow-item">
|
||||
<div class="step-index">2</div>
|
||||
<div class="step-card">
|
||||
<div class="step-header"><div class="title">选择亚马逊商家账号</div></div>
|
||||
<div class="desc">请确保账号地区与专利地区一致,不一致可能导致结果不准确或失败。</div>
|
||||
|
||||
<el-select v-model="selectedAccount" placeholder="选择账号" size="small" style="width: 100%">
|
||||
<el-option v-for="opt in accountOptions" :key="opt.value" :label="opt.label" :value="opt.value">
|
||||
<div class="account-option">
|
||||
<span>{{ opt.label }}</span>
|
||||
<span class="account-status">{{ opt.status }}</span>
|
||||
<span class="account-check">✓</span>
|
||||
</div>
|
||||
</el-option>
|
||||
</el-select>
|
||||
|
||||
<div class="step-actions btn-row">
|
||||
<el-button size="small" class="w50">添加账号</el-button>
|
||||
<el-button size="small" class="w50 btn-blue">账号管理</el-button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 3. 选择产品地理区域 -->
|
||||
<div class="flow-item">
|
||||
<div class="step-index">3</div>
|
||||
<div class="step-card">
|
||||
<div class="step-header"><div class="title">选择产品品牌地区</div></div>
|
||||
<div class="desc">暂时仅支持美国品牌商标筛查,后续将开放更多地区,敬请期待。</div>
|
||||
<el-select v-model="region" placeholder="选择地区" size="small" style="width: 100%">
|
||||
<el-option v-for="opt in regionOptions" :key="opt.value" :label="opt.label" :value="opt.value">
|
||||
<span style="margin-right:6px">{{ opt.flag }}</span>{{ opt.label }}
|
||||
</el-option>
|
||||
</el-select>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 4. 选择需查询的(可多选) -->
|
||||
<div class="flow-item">
|
||||
<div class="step-index">4</div>
|
||||
<div class="step-card">
|
||||
<div class="step-header"><div class="title">选择需查询的(可多选)</div></div>
|
||||
<div class="desc">默认查询违规产品,可多选</div>
|
||||
|
||||
<div class="query-options">
|
||||
<div :class="['query-card', { active: queryTypes.includes('product') }]" @click="toggleQueryType('product')">
|
||||
<div class="query-check">
|
||||
<div class="check-icon" v-if="queryTypes.includes('product')">✓</div>
|
||||
</div>
|
||||
<div class="query-content">
|
||||
<div class="query-title">产品商标筛查</div>
|
||||
<div class="query-desc">筛查未注册商标或TM标的商品</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div :class="['query-card', { active: queryTypes.includes('brand') }]" @click="toggleQueryType('brand')">
|
||||
<div class="query-check">
|
||||
<div class="check-icon" v-if="queryTypes.includes('brand')">✓</div>
|
||||
</div>
|
||||
<div class="query-content">
|
||||
<div class="query-title">品牌商标筛查</div>
|
||||
<div class="query-desc">筛查未注册商标的品牌</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div :class="['query-card', { active: queryTypes.includes('platform') }]" @click="toggleQueryType('platform')">
|
||||
<div class="query-check">
|
||||
<div class="check-icon" v-if="queryTypes.includes('platform')">✓</div>
|
||||
</div>
|
||||
<div class="query-content">
|
||||
<div class="query-title">跟卖许可筛查</div>
|
||||
<div class="query-desc">筛查亚马逊许可跟卖的商品</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 底部开始查询按钮 -->
|
||||
<div class="bottom-action">
|
||||
<div class="action-header">
|
||||
<span class="step-indicator">{{ trademarkLoading ? currentStep : 1 }}/4</span>
|
||||
<el-button class="start-btn" type="primary" :disabled="!trademarkFileName || trademarkLoading" :loading="trademarkLoading" @click="startTrademarkQuery">
|
||||
开始筛查
|
||||
</el-button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<TrialExpiredDialog v-model="showTrialExpiredDialog" :expired-type="trialExpiredType" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
.trademark-panel {
|
||||
flex: 1;
|
||||
min-height: 0;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
overflow: hidden;
|
||||
}
|
||||
.steps-flow {
|
||||
position: relative;
|
||||
flex: 1;
|
||||
min-height: 0;
|
||||
overflow-y: auto;
|
||||
scrollbar-width: none;
|
||||
}
|
||||
.steps-flow::-webkit-scrollbar {
|
||||
display: none;
|
||||
}
|
||||
.steps-flow:before { content: ''; position: absolute; left: 13px; top: 26px; bottom: 0; width: 2px; background: rgba(229, 231, 235, 0.6); }
|
||||
.flow-item { position: relative; display: grid; grid-template-columns: 28px 1fr; gap: 12px; padding: 10px 0; }
|
||||
.flow-item .step-index { position: static; width: 28px; height: 28px; line-height: 28px; text-align: center; border-radius: 50%; background: #1677FF; color: #fff; font-size: 14px; font-weight: 600; margin-top: 2px; }
|
||||
.step-card { border: none; border-radius: 0; padding: 0; background: transparent; }
|
||||
.step-header { display: flex; align-items: center; gap: 8px; margin-bottom: 8px; }
|
||||
.title { font-size: 14px; font-weight: 600; color: #303133; text-align: left; }
|
||||
.desc { font-size: 12px; color: #909399; margin-bottom: 10px; text-align: left; line-height: 1.5; }
|
||||
.links { display: flex; align-items: center; gap: 6px; margin-bottom: 8px; }
|
||||
.link { color: #409EFF; cursor: pointer; font-size: 12px; }
|
||||
|
||||
.file-chip {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 6px;
|
||||
padding: 6px 8px;
|
||||
background: #f5f7fa;
|
||||
border-radius: 4px;
|
||||
font-size: 12px;
|
||||
color: #606266;
|
||||
margin-top: 6px;
|
||||
}
|
||||
.file-chip .dot {
|
||||
width: 6px;
|
||||
height: 6px;
|
||||
background: #409EFF;
|
||||
border-radius: 50%;
|
||||
display: inline-block;
|
||||
}
|
||||
.file-chip .name {
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.dropzone {
|
||||
border: 1px dashed #c0c4cc;
|
||||
border-radius: 8px;
|
||||
padding: 20px 16px;
|
||||
text-align: center;
|
||||
cursor: pointer;
|
||||
background: #fafafa;
|
||||
transition: all 0.2s ease;
|
||||
}
|
||||
.dropzone:hover { background: #f6fbff; border-color: #409EFF; }
|
||||
.dz-icon { font-size: 20px; margin-bottom: 6px; color: #909399; }
|
||||
.dz-text { color: #303133; font-size: 13px; margin-bottom: 2px; }
|
||||
.dz-sub { color: #909399; font-size: 12px; }
|
||||
|
||||
.query-options {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 8px;
|
||||
}
|
||||
.query-card {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
padding: 8px 12px;
|
||||
gap: 10px;
|
||||
width: 100%;
|
||||
min-height: 46px;
|
||||
border-radius: 6px;
|
||||
border: 1px solid #e5e7eb;
|
||||
background: #ffffff;
|
||||
cursor: pointer;
|
||||
transition: all 0.2s ease;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
.query-card:hover {
|
||||
border-color: #1677FF;
|
||||
background: #f7fbff;
|
||||
}
|
||||
.query-card.active {
|
||||
border-color: #1677FF;
|
||||
background: #f0f9ff;
|
||||
}
|
||||
.query-check {
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
border-radius: 50%;
|
||||
border: 1.5px solid #d9d9d9;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
flex-shrink: 0;
|
||||
background: #ffffff;
|
||||
transition: all 0.2s ease;
|
||||
}
|
||||
.query-card.active .query-check {
|
||||
border-color: #1677FF;
|
||||
background: #1677FF;
|
||||
}
|
||||
.check-icon {
|
||||
color: #ffffff;
|
||||
font-size: 10px;
|
||||
font-weight: bold;
|
||||
line-height: 1;
|
||||
}
|
||||
.query-content {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 2px;
|
||||
align-items: flex-start;
|
||||
min-width: 0;
|
||||
}
|
||||
.query-title {
|
||||
font-size: 13px;
|
||||
font-weight: 600;
|
||||
color: #303133;
|
||||
line-height: 1.3;
|
||||
text-align: left;
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
width: 100%;
|
||||
}
|
||||
.query-desc {
|
||||
font-size: 11px;
|
||||
color: #909399;
|
||||
line-height: 1.3;
|
||||
text-align: left;
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.step-actions { margin-top: 8px; }
|
||||
.btn-row { display: grid; grid-template-columns: 1fr 1fr; gap: 8px; }
|
||||
.w50 { width: 100%; }
|
||||
|
||||
.bottom-action {
|
||||
flex-shrink: 0;
|
||||
padding: 16px 0 0 0;
|
||||
border-top: 2px solid #e5e7eb;
|
||||
}
|
||||
.action-header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 10px;
|
||||
}
|
||||
.step-indicator {
|
||||
font-size: 15px;
|
||||
color: #303133;
|
||||
font-weight: 600;
|
||||
min-width: 36px;
|
||||
text-align: left;
|
||||
}
|
||||
.start-btn {
|
||||
flex: 1;
|
||||
height: 38px;
|
||||
background: #1677FF;
|
||||
border-color: #1677FF;
|
||||
font-size: 14px;
|
||||
font-weight: 500;
|
||||
border-radius: 6px;
|
||||
}
|
||||
|
||||
.btn-blue { background: #1677FF; border-color: #1677FF; color: #fff; }
|
||||
.btn-blue:disabled { background: #a6c8ff; border-color: #a6c8ff; color: #fff; }
|
||||
|
||||
.account-option {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
width: 100%;
|
||||
}
|
||||
.account-status {
|
||||
margin-left: auto;
|
||||
font-size: 12px;
|
||||
color: #909399;
|
||||
}
|
||||
.account-check {
|
||||
color: #1677FF;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.trademark-panel :deep(.el-select),
|
||||
.trademark-panel :deep(.el-input__wrapper) {
|
||||
width: 100%;
|
||||
}
|
||||
.trademark-panel :deep(.el-select .el-input__wrapper) {
|
||||
border-radius: 6px;
|
||||
}
|
||||
.trademark-panel :deep(.el-button) {
|
||||
border-radius: 6px;
|
||||
}
|
||||
</style>
|
||||
|
||||
Reference in New Issue
Block a user