完善
This commit is contained in:
347
pages/mall/admin/product/product-management/edit.uvue
Normal file
347
pages/mall/admin/product/product-management/edit.uvue
Normal file
@@ -0,0 +1,347 @@
|
||||
<template>
|
||||
<view class="product-edit-page">
|
||||
<view class="page-header">
|
||||
<view class="back-link" @click="goBack">
|
||||
<text class="arrow">{"<"}</text>
|
||||
<text class="back-txt">返回</text>
|
||||
</view>
|
||||
<text class="header-title">编辑商品</text>
|
||||
</view>
|
||||
|
||||
<!-- 步骤层 -->
|
||||
<view class="steps-card">
|
||||
<view class="step-items">
|
||||
<view v-for="(step, index) in steps" :key="index" class="step-item" :class="{ active: activeStep === index }">
|
||||
<text class="step-txt">{{ step }}</text>
|
||||
<view v-if="index < steps.length - 1" class="step-line"></view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 表单内容 -->
|
||||
<view class="form-card">
|
||||
<view class="form-item">
|
||||
<view class="label"><text class="required">*</text><text>商品类型:</text></view>
|
||||
<view class="input-wrap">
|
||||
<view class="radio-group">
|
||||
<view class="radio-item active">
|
||||
<text class="radio-circle on"></text>
|
||||
<view class="radio-txt">
|
||||
<text class="main">普通商品</text>
|
||||
<text class="sub">(物流发货)</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class="form-item">
|
||||
<view class="label"><text class="required">*</text><text>商品名称:</text></view>
|
||||
<view class="input-wrap">
|
||||
<view class="input-box">
|
||||
<input class="real-input" value="UR2024夏季新款女装复古纯欲氛围感一字肩短款T恤衫UWG440060" />
|
||||
<text class="count">36/80</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class="form-item">
|
||||
<view class="label"><text class="required">*</text><text>单位:</text></view>
|
||||
<view class="input-wrap">
|
||||
<view class="input-box small">
|
||||
<input class="real-input" value="件" />
|
||||
<text class="count">1/5</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class="form-item">
|
||||
<view class="label"><text class="required">*</text><text>商品轮播图:</text></view>
|
||||
<view class="input-wrap">
|
||||
<view class="image-uploader">
|
||||
<view v-for="(img, i) in carouselImages" :key="i" class="img-item">
|
||||
<image :src="img" mode="aspectFill" />
|
||||
<view class="img-close">×</view>
|
||||
</view>
|
||||
<view class="upload-btn">
|
||||
<text class="icon">+</text>
|
||||
</view>
|
||||
</view>
|
||||
<text class="tip">建议尺寸:800*800,可拖拽改变图片顺序,默认首张图为主图,最多上传10张</text>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class="form-item">
|
||||
<view class="label"><text>添加视频:</text></view>
|
||||
<view class="input-wrap">
|
||||
<view class="upload-btn v-btn">
|
||||
<text class="v-icon">📹</text>
|
||||
</view>
|
||||
<text class="tip">建议时长:9~30秒,视频宽高比16:9</text>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class="form-item">
|
||||
<view class="label"><text class="required">*</text><text>商品分类:</text></view>
|
||||
<view class="input-wrap">
|
||||
<view class="tag-selector">
|
||||
<view v-for="tag in categories" :key="tag" class="tag-item">
|
||||
<text>{{ tag }}</text>
|
||||
<text class="close">×</text>
|
||||
</view>
|
||||
<text class="add-link">新增分类</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class="form-item">
|
||||
<view class="label"><text>商品标签:</text></view>
|
||||
<view class="input-wrap">
|
||||
<view class="mock-btn-select">选择标签</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class="form-item">
|
||||
<view class="label"><text>商品状态:</text></view>
|
||||
<view class="input-wrap">
|
||||
<view class="radio-group-simple">
|
||||
<view class="radio-simple on">
|
||||
<text class="dot"></text>
|
||||
<text>上架</text>
|
||||
</view>
|
||||
<view class="radio-simple">
|
||||
<text class="dot"></text>
|
||||
<text>下架</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class="footer-btns">
|
||||
<button class="btn-next">下一步</button>
|
||||
<button class="btn-save">保存</button>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script setup lang="uts">
|
||||
import { ref } from 'vue'
|
||||
import { openRoute } from '@/layouts/admin/store/adminNavStore.uts'
|
||||
|
||||
const activeStep = ref(0)
|
||||
const steps = ['基础信息', '规格库存', '商品详情', '物流设置', '会员价/佣金', '营销设置', '其他设置']
|
||||
|
||||
const carouselImages = ref([
|
||||
'https://img1.baidu.com/it/u=254065646,3100346083&fm=253&fmt=auto&app=138&f=JPEG?w=500&h=500',
|
||||
'https://img2.baidu.com/it/u=3025255470,3051061730&fm=253&fmt=auto&app=138&f=JPEG?w=500&h=500',
|
||||
'https://img2.baidu.com/it/u=3775079632,546700868&fm=253&fmt=auto&app=138&f=JPEG?w=500&h=500'
|
||||
])
|
||||
|
||||
const categories = ref(['生活家居', '运动专区 / 361', '运动专区 / 特步', '运动专区 / 匹克'])
|
||||
|
||||
function goBack() {
|
||||
openRoute('product_productList')
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.product-edit-page {
|
||||
padding: 20px;
|
||||
background-color: #f5f7f9;
|
||||
min-height: 100vh;
|
||||
}
|
||||
|
||||
.page-header {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
gap: 16px;
|
||||
margin-bottom: 20px;
|
||||
.back-link {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
gap: 4px;
|
||||
color: #666;
|
||||
cursor: pointer;
|
||||
.arrow { font-size: 14px; }
|
||||
.back-txt { font-size: 14px; }
|
||||
}
|
||||
.header-title { font-size: 16px; font-weight: bold; color: #333; }
|
||||
}
|
||||
|
||||
.steps-card {
|
||||
background: #fff;
|
||||
padding: 20px;
|
||||
border-radius: 4px;
|
||||
margin-bottom: 16px;
|
||||
}
|
||||
|
||||
.step-items {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.step-item {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
.step-txt {
|
||||
font-size: 14px;
|
||||
color: #999;
|
||||
padding: 0 16px;
|
||||
}
|
||||
&.active .step-txt {
|
||||
color: #1890ff;
|
||||
font-weight: bold;
|
||||
border-bottom: 2px solid #1890ff;
|
||||
padding-bottom: 4px;
|
||||
}
|
||||
.step-line {
|
||||
width: 20px;
|
||||
height: 1px;
|
||||
background: #e8e8e8;
|
||||
}
|
||||
}
|
||||
|
||||
.form-card {
|
||||
background: #fff;
|
||||
padding: 40px;
|
||||
border-radius: 4px;
|
||||
}
|
||||
|
||||
.form-item {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
margin-bottom: 30px;
|
||||
.label {
|
||||
width: 120px;
|
||||
text-align: right;
|
||||
font-size: 14px;
|
||||
color: #333;
|
||||
padding-top: 8px;
|
||||
margin-right: 20px;
|
||||
.required { color: #f5222d; margin-right: 4px; }
|
||||
}
|
||||
.input-wrap { flex: 1; }
|
||||
}
|
||||
|
||||
.radio-item {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
border: 1px solid #1890ff;
|
||||
border-radius: 4px;
|
||||
padding: 10px 16px;
|
||||
width: 160px;
|
||||
position: relative;
|
||||
.radio-circle {
|
||||
width: 14px; height: 14px; border: 1px solid #d9d9d9; border-radius: 50%;
|
||||
&.on { border-color: #1890ff; background: #1890ff; }
|
||||
}
|
||||
.radio-txt {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
.main { font-size: 14px; color: #333; }
|
||||
.sub { font-size: 12px; color: #999; }
|
||||
}
|
||||
&::after {
|
||||
content: '✓';
|
||||
position: absolute;
|
||||
right: 0; bottom: 0;
|
||||
background: #1890ff; color: #fff; font-size: 10px; padding: 0 2px;
|
||||
}
|
||||
}
|
||||
|
||||
.input-box {
|
||||
border: 1px solid #d9d9d9;
|
||||
border-radius: 4px;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
padding: 0 12px;
|
||||
width: 400px;
|
||||
height: 36px;
|
||||
&.small { width: 150px; }
|
||||
.real-input { flex: 1; font-size: 14px; color: #333; }
|
||||
.count { font-size: 12px; color: #bfbfbf; }
|
||||
}
|
||||
|
||||
.image-uploader {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
flex-wrap: wrap;
|
||||
gap: 12px;
|
||||
margin-bottom: 8px;
|
||||
.img-item {
|
||||
width: 80px; height: 80px; position: relative;
|
||||
image { width: 100%; height: 100%; border-radius: 4px; }
|
||||
.img-close {
|
||||
position: absolute; right: -6px; top: -6px; width: 16px; height: 16px;
|
||||
background: rgba(0,0,0,0.5); color: #fff; border-radius: 50%;
|
||||
display: flex; align-items: center; justify-content: center; font-size: 12px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.upload-btn {
|
||||
width: 80px; height: 80px; border: 1px dashed #d9d9d9; border-radius: 4px;
|
||||
display: flex; align-items: center; justify-content: center;
|
||||
.icon { font-size: 24px; color: #999; }
|
||||
&.v-btn { width: 64px; height: 64px; margin-bottom: 8px; .v-icon { font-size: 24px; } }
|
||||
}
|
||||
|
||||
.tip { font-size: 12px; color: #999; }
|
||||
|
||||
.tag-selector {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
flex-wrap: wrap;
|
||||
gap: 8px;
|
||||
align-items: center;
|
||||
.tag-item {
|
||||
background: #f5f5f5; border: 1px solid #d9d9d9; padding: 2px 10px; border-radius: 4px;
|
||||
display: flex; flex-direction: row; align-items: center; gap: 6px;
|
||||
font-size: 14px; color: #666;
|
||||
.close { color: #999; cursor: pointer; }
|
||||
}
|
||||
.add-link { font-size: 14px; color: #1890ff; cursor: pointer; }
|
||||
}
|
||||
|
||||
.mock-btn-select {
|
||||
border: 1px solid #d9d9d9; border-radius: 4px; padding: 6px 16px;
|
||||
font-size: 14px; color: #666; display: inline-block;
|
||||
}
|
||||
|
||||
.radio-group-simple {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
gap: 20px;
|
||||
.radio-simple {
|
||||
display: flex; flex-direction: row; align-items: center; gap: 6px; font-size: 14px; color: #666;
|
||||
.dot { width: 14px; height: 14px; border: 1px solid #d9d9d9; border-radius: 50%; position: relative; }
|
||||
&.on {
|
||||
color: #1890ff;
|
||||
.dot { border-color: #1890ff; }
|
||||
.dot::after {
|
||||
content: ''; position: absolute; left: 3px; top: 3px; width: 6px; height: 6px;
|
||||
background: #1890ff; border-radius: 50%;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.footer-btns {
|
||||
margin-top: 24px;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
justify-content: center;
|
||||
gap: 16px;
|
||||
padding-bottom: 40px;
|
||||
.btn-next { background: #1890ff; color: #fff; border: none; padding: 0 24px; height: 40px; border-radius: 4px; }
|
||||
.btn-save { background: #fff; color: #1890ff; border: 1px solid #1890ff; padding: 0 24px; height: 40px; border-radius: 4px; }
|
||||
}
|
||||
</style>
|
||||
@@ -1,25 +1,616 @@
|
||||
<template>
|
||||
<AdminLayout :currentPage="currentPage">
|
||||
<view class="page">
|
||||
<view class="header">
|
||||
<text class="title">{{ title }}</text>
|
||||
<text class="sub-title">页面已修复 (UTF-8)</text>
|
||||
<view class="product-list-page">
|
||||
<!-- 1. 搜索表单 -->
|
||||
<view class="search-card">
|
||||
<view class="search-row">
|
||||
<view class="search-item">
|
||||
<text class="label">商品搜索:</text>
|
||||
<input class="mock-input" placeholder="请输入商品名称/关键字/ID" />
|
||||
</view>
|
||||
<view class="search-item">
|
||||
<text class="label">商品类型:</text>
|
||||
<view class="mock-select">
|
||||
<text>全部</text>
|
||||
<text class="arrow">▼</text>
|
||||
</view>
|
||||
</view>
|
||||
<view class="search-item">
|
||||
<text class="label">商品分类:</text>
|
||||
<view class="mock-select">
|
||||
<text>请选择</text>
|
||||
<text class="arrow">▼</text>
|
||||
</view>
|
||||
</view>
|
||||
<view class="search-btns">
|
||||
<button class="btn-primary">查询</button>
|
||||
<button class="btn-reset">重置</button>
|
||||
<view class="expand-control">
|
||||
<text class="expand-txt">展开</text>
|
||||
<text class="expand-arrow">▼</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
<view class="search-row mt-12">
|
||||
<view class="search-item">
|
||||
<text class="label">配送方式:</text>
|
||||
<view class="mock-select">
|
||||
<text>全部</text>
|
||||
<text class="arrow">▼</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</AdminLayout>
|
||||
|
||||
<!-- 2. 商品状态 Tabs -->
|
||||
<view class="status-tabs-wrap">
|
||||
<view class="status-tabs">
|
||||
<view
|
||||
v-for="(tab, index) in statusTabs"
|
||||
:key="index"
|
||||
class="tab-item"
|
||||
:class="{ active: activeStatus === tab.key }"
|
||||
@click="activeStatus = tab.key"
|
||||
>
|
||||
<text>{{ tab.label }}({{ tab.count }})</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 3. 操作按钮行 -->
|
||||
<view class="action-bar">
|
||||
<view class="left-actions">
|
||||
<button class="btn-add" @click="goEdit(null)">添加商品</button>
|
||||
<button class="btn-collect">商品采集</button>
|
||||
<view class="btn-dropdown">
|
||||
<text>批量修改</text>
|
||||
<text class="arrow">▼</text>
|
||||
</view>
|
||||
<view class="btn-dropdown">
|
||||
<text>商品迁移</text>
|
||||
<text class="arrow">▼</text>
|
||||
</view>
|
||||
<button class="btn-export">数据导出</button>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 4. 商品列表表格 -->
|
||||
<view class="list-card">
|
||||
<view class="table-v5">
|
||||
<view class="th-row">
|
||||
<view class="th col-check"><text>□</text></view>
|
||||
<view class="th col-id"><text>商品ID</text></view>
|
||||
<view class="th col-img"><text>商品图</text></view>
|
||||
<view class="th col-name"><text>商品名称</text></view>
|
||||
<view class="th col-activity"><text>参与活动</text></view>
|
||||
<view class="th col-type"><text>商品类型</text></view>
|
||||
<view class="th col-price"><text>商品售价</text></view>
|
||||
<view class="th col-sales"><text>销量</text></view>
|
||||
<view class="th col-stock"><text>库存</text></view>
|
||||
<view class="th col-sort"><text>排序</text></view>
|
||||
<view class="th col-status"><text>状态</text></view>
|
||||
<view class="th col-op"><text>操作</text></view>
|
||||
</view>
|
||||
|
||||
<view v-for="(item, index) in productList" :key="index"
|
||||
class="tr-row"
|
||||
:style="{ zIndex: activeDropdownId === item.id ? 1000 : 1 }"
|
||||
>
|
||||
<view class="td col-check"><text>□</text></view>
|
||||
<view class="td col-id"><text>{{ item.id }}</text></view>
|
||||
<view class="td col-img">
|
||||
<image class="p-img" :src="item.image" mode="aspectFill" />
|
||||
</view>
|
||||
<view class="td col-name">
|
||||
<text class="p-name-txt">{{ item.name }}</text>
|
||||
</view>
|
||||
<view class="td col-activity">
|
||||
<view class="activity-tags">
|
||||
<text v-for="tag in item.activities" :key="tag" class="tag" :class="tag">{{ getActivityName(tag) }}</text>
|
||||
<text v-if="item.activities.length === 0">-</text>
|
||||
</view>
|
||||
</view>
|
||||
<view class="td col-type"><text>{{ item.typeName }}</text></view>
|
||||
<view class="td col-price"><text>{{ item.price }}</text></view>
|
||||
<view class="td col-sales"><text>{{ item.sales }}</text></view>
|
||||
<view class="td col-stock"><text>{{ item.stock }}</text></view>
|
||||
<view class="td col-sort"><text>{{ item.sort }}</text></view>
|
||||
<view class="td col-status">
|
||||
<view class="mock-switch" :class="{ on: item.status === 1 }">
|
||||
<text class="switch-txt">{{ item.status === 1 ? '上架' : '下架' }}</text>
|
||||
<view class="switch-dot"></view>
|
||||
</view>
|
||||
</view>
|
||||
<view class="td col-op op-group">
|
||||
<text class="op-link" @click.stop="goEdit(item.id)">编辑</text>
|
||||
<text class="op-divider">|</text>
|
||||
<view class="more-hover-box"
|
||||
@mouseenter="activeDropdownId = item.id"
|
||||
@mouseleave="activeDropdownId = null"
|
||||
>
|
||||
<view class="more-trigger-txt">
|
||||
<text class="more-link-text">更多</text>
|
||||
<text class="more-arrow-icon">∨</text>
|
||||
</view>
|
||||
<view class="dropdown-list-container" v-show="activeDropdownId === item.id">
|
||||
<view class="dropdown-triangle"></view>
|
||||
<view class="dropdown-menu-body">
|
||||
<text class="menu-item" @click.stop="goReviews(item.id)">查看评论</text>
|
||||
<text class="menu-item" @click.stop="goMemberPrice(item.id)">会员价管理</text>
|
||||
<text class="menu-item" @click.stop="uni.showToast({title:'佣金管理开发中', icon:'none'})">佣金管理</text>
|
||||
<text class="menu-item danger-item" @click.stop="moveToRecycle(item.id)">{{ activeStatus === 'recycle' ? '恢复商品' : '移到回收站' }}</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 5. 分页 -->
|
||||
<view class="pagination-row">
|
||||
<text class="total">共 {{ total }} 条</text>
|
||||
<view class="page-ctrl">
|
||||
<text class="page-btn disabled">{"<"}</text>
|
||||
<text class="page-num active">1</text>
|
||||
<text class="page-num">2</text>
|
||||
<text class="page-btn">{">"}</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script setup lang="uts">
|
||||
import { ref } from 'vue'
|
||||
import AdminLayout from '@/layouts/admin/AdminLayout.uvue'
|
||||
const currentPage = ref<string>('product-list')
|
||||
const title = ref<string>('index')
|
||||
import { openRoute } from '@/layouts/admin/store/adminNavStore.uts'
|
||||
|
||||
const total = ref(49)
|
||||
const activeStatus = ref('selling')
|
||||
const activeDropdownId = ref<number | null>(null)
|
||||
|
||||
const statusTabs = ref([
|
||||
{ key: 'selling', label: '出售中的商品', count: 49 },
|
||||
{ key: 'warehouse', label: '仓库中的商品', count: 4 },
|
||||
{ key: 'soldout', label: '已经售罄商品', count: 11 },
|
||||
{ key: 'alarm', label: '警戒库存商品', count: 27 },
|
||||
{ key: 'recycle', label: '回收站的商品', count: 176 },
|
||||
])
|
||||
|
||||
const productList = ref([
|
||||
{
|
||||
id: 963,
|
||||
image: 'https://img1.baidu.com/it/u=254065646,3100346083&fm=253&fmt=auto&app=138&f=JPEG?w=500&h=500',
|
||||
name: 'UR2024夏季新款女装复古纯欲氛围感一字肩短款T恤衫UWG440060',
|
||||
activities: ['kj', 'pt'],
|
||||
typeName: '普通商品',
|
||||
price: '0.01',
|
||||
sales: 639,
|
||||
stock: 1602,
|
||||
sort: 9999,
|
||||
status: 1
|
||||
},
|
||||
{
|
||||
id: 108,
|
||||
image: 'https://img2.baidu.com/it/u=3033501986,2204481084&fm=253&fmt=auto&app=138&f=JPEG?w=569&h=500',
|
||||
name: 'FOMIX 蛋壳椅 进口头层牛皮橙色单人沙发椅Egg chair设计师师单椅单沙头层牛皮/单椅',
|
||||
activities: ['pt', 'ms'],
|
||||
typeName: '普通商品',
|
||||
price: '7580.00',
|
||||
sales: 14,
|
||||
stock: 16638,
|
||||
sort: 9999,
|
||||
status: 1
|
||||
},
|
||||
{
|
||||
id: 48,
|
||||
image: 'https://img0.baidu.com/it/u=1762118431,3101886131&fm=253&fmt=auto&app=138&f=JPEG?w=500&h=500',
|
||||
name: '阿迪达斯官网 adidas BBALL CAP COT 男女训练运动帽子FQ5270 传奇墨水蓝/传奇墨水蓝/白 XL',
|
||||
activities: ['kj', 'pt', 'ms'],
|
||||
typeName: '普通商品',
|
||||
price: '100.00',
|
||||
sales: 841,
|
||||
stock: 2318,
|
||||
sort: 9998,
|
||||
status: 1
|
||||
}
|
||||
])
|
||||
|
||||
function getActivityName(tag: string): string {
|
||||
if (tag === 'kj') return '砍价'
|
||||
if (tag === 'pt') return '拼团'
|
||||
if (tag === 'ms') return '秒杀'
|
||||
return tag
|
||||
}
|
||||
|
||||
function goEdit(id: number | null) {
|
||||
openRoute('product_edit')
|
||||
}
|
||||
|
||||
function goReviews(id: number) {
|
||||
openRoute('product_productReply')
|
||||
}
|
||||
|
||||
function goMemberPrice(id: number) {
|
||||
openRoute('product_member_price')
|
||||
}
|
||||
|
||||
function moveToRecycle(id: number) {
|
||||
const action = activeStatus.value === 'recycle' ? '恢复' : '移到回收站';
|
||||
uni.showModal({
|
||||
title: '提示',
|
||||
content: `确认要将该商品${action}吗?`,
|
||||
success: (res) => {
|
||||
if (res.confirm) {
|
||||
uni.showToast({ title: '操作成功', icon: 'success' });
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
@import '@/uni.scss';
|
||||
.page { padding: $space-lg; }
|
||||
.header { padding: $space-lg; border-radius: $radius; background: $background-primary; box-shadow: $shadow-xs; }
|
||||
.title { font-size: $font-size-lg; font-weight: $font-weight-bold; color: $text-primary; }
|
||||
.sub-title { margin-top: $space-xs; font-size: $font-size-md; color: $text-secondary; }
|
||||
.product-list-page {
|
||||
padding: 20px;
|
||||
background-color: #f5f7f9;
|
||||
min-height: 100vh;
|
||||
}
|
||||
|
||||
.search-card {
|
||||
background: #fff;
|
||||
padding: 24px;
|
||||
border-radius: 4px;
|
||||
margin-bottom: 16px;
|
||||
}
|
||||
|
||||
.search-row {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
flex-wrap: wrap;
|
||||
gap: 24px;
|
||||
}
|
||||
.mt-12 { margin-top: 12px; }
|
||||
|
||||
.search-item {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
.label { font-size: 14px; color: #606266; width: 80px; text-align: right; }
|
||||
}
|
||||
|
||||
.mock-input {
|
||||
width: 200px;
|
||||
height: 32px;
|
||||
border: 1px solid #dcdfe6;
|
||||
border-radius: 4px;
|
||||
padding: 0 12px;
|
||||
font-size: 13px;
|
||||
}
|
||||
|
||||
.mock-select {
|
||||
width: 160px;
|
||||
height: 32px;
|
||||
border: 1px solid #dcdfe6;
|
||||
border-radius: 4px;
|
||||
padding: 0 12px;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
font-size: 13px;
|
||||
color: #606266;
|
||||
.arrow { font-size: 10px; color: #c0c4cc; }
|
||||
}
|
||||
|
||||
.search-btns {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
gap: 12px;
|
||||
}
|
||||
|
||||
.btn-primary { background: #1890ff; color: #fff; height: 32px; padding: 0 16px; border-radius: 4px; font-size: 13px; border: none; }
|
||||
.btn-reset { background: #fff; color: #606266; height: 32px; padding: 0 16px; border-radius: 4px; font-size: 13px; border: 1px solid #dcdfe6; }
|
||||
.expand-control { display: flex; flex-direction: row; align-items: center; gap: 4px; cursor: pointer; }
|
||||
.expand-txt { font-size: 13px; color: #1890ff; }
|
||||
.expand-arrow { font-size: 10px; color: #1890ff; }
|
||||
|
||||
.status-tabs-wrap {
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
.status-tabs {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
border-bottom: 2px solid #f0f2f5;
|
||||
}
|
||||
|
||||
.tab-item {
|
||||
padding: 12px 20px;
|
||||
font-size: 14px;
|
||||
color: #606266;
|
||||
position: relative;
|
||||
cursor: pointer;
|
||||
&.active {
|
||||
color: #1890ff;
|
||||
&::after {
|
||||
content: '';
|
||||
position: absolute;
|
||||
bottom: -2px;
|
||||
left: 0;
|
||||
right: 0;
|
||||
height: 2px;
|
||||
background: #1890ff;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.action-bar {
|
||||
margin-bottom: 16px;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
.left-actions {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
gap: 12px;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.btn-add { background: #1890ff; color: #fff; height: 32px; padding: 0 12px; border-radius: 4px; font-size: 13px; border: none; }
|
||||
.btn-collect { background: #13ce66; color: #fff; height: 32px; padding: 0 12px; border-radius: 4px; font-size: 13px; border: none; }
|
||||
.btn-export { background: #fff; color: #606266; height: 32px; padding: 0 12px; border-radius: 4px; font-size: 13px; border: 1px solid #dcdfe6; }
|
||||
|
||||
.btn-dropdown {
|
||||
height: 32px;
|
||||
padding: 0 12px;
|
||||
border: 1px solid #dcdfe6;
|
||||
border-radius: 4px;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
gap: 6px;
|
||||
font-size: 13px;
|
||||
color: #606266;
|
||||
.arrow { font-size: 10px; color: #c4cc; }
|
||||
}
|
||||
|
||||
.list-card {
|
||||
background: #fff;
|
||||
border-radius: 4px;
|
||||
padding-bottom: 20px;
|
||||
position: relative;
|
||||
overflow: visible;
|
||||
}
|
||||
|
||||
.table-v5 {
|
||||
width: 100%;
|
||||
overflow: visible;
|
||||
}
|
||||
|
||||
.th-row {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
background-color: #f2f2f2;
|
||||
}
|
||||
|
||||
.th {
|
||||
padding: 12px 8px;
|
||||
font-size: 13px;
|
||||
font-weight: bold;
|
||||
color: #333;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.tr-row {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
border-bottom: 1px solid #f0f0f0;
|
||||
position: relative;
|
||||
overflow: visible;
|
||||
&:hover { background-color: #fafafa; }
|
||||
}
|
||||
|
||||
.td {
|
||||
padding: 12px 8px;
|
||||
font-size: 13px;
|
||||
color: #606266;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.col-check { width: 50px; }
|
||||
.col-id { width: 80px; }
|
||||
.col-img { width: 80px; }
|
||||
.col-name { flex: 1; justify-content: flex-start; text-align: left; }
|
||||
.col-activity { width: 140px; }
|
||||
.col-type { width: 100px; }
|
||||
.col-price { width: 100px; }
|
||||
.col-sales { width: 80px; }
|
||||
.col-stock { width: 80px; }
|
||||
.col-sort { width: 80px; }
|
||||
.col-status { width: 100px; }
|
||||
.col-op { width: 150px; }
|
||||
|
||||
.op-group {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.more-hover-box {
|
||||
position: relative;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
height: 40px;
|
||||
padding: 0 10px;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.more-trigger-txt {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
pointer-events: none; /* 让事件透传给 more-hover-box */
|
||||
}
|
||||
|
||||
.more-link-text {
|
||||
font-size: 13px;
|
||||
color: #1890ff;
|
||||
}
|
||||
|
||||
.more-arrow-icon {
|
||||
font-size: 10px;
|
||||
color: #1890ff;
|
||||
margin-left: 2px;
|
||||
}
|
||||
|
||||
.dropdown-list-container {
|
||||
position: absolute;
|
||||
top: 35px;
|
||||
right: -10px;
|
||||
width: 120px;
|
||||
padding-top: 8px; /* 增加感应连续性 */
|
||||
z-index: 9999;
|
||||
}
|
||||
|
||||
.dropdown-triangle {
|
||||
position: absolute;
|
||||
top: 2px;
|
||||
right: 25px;
|
||||
width: 0;
|
||||
height: 0;
|
||||
border-left: 6px solid transparent;
|
||||
border-right: 6px solid transparent;
|
||||
border-bottom: 6px solid #fff;
|
||||
}
|
||||
|
||||
.dropdown-menu-body {
|
||||
background: #fff;
|
||||
border-radius: 4px;
|
||||
box-shadow: 0 2px 12px 0 rgba(0,0,0,0.1);
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
padding: 6px 0;
|
||||
}
|
||||
|
||||
.menu-item {
|
||||
padding: 8px 16px;
|
||||
font-size: 14px;
|
||||
color: #606266;
|
||||
text-align: center;
|
||||
line-height: 1.5;
|
||||
&:hover {
|
||||
background-color: #f5f7fa;
|
||||
color: #1890ff;
|
||||
}
|
||||
}
|
||||
|
||||
.danger-item {
|
||||
&:hover {
|
||||
color: #ff4d4f;
|
||||
}
|
||||
}
|
||||
|
||||
.p-img { width: 40px; height: 40px; border-radius: 4px; }
|
||||
.p-name-txt { font-size: 13px; line-height: 1.4; color: #333; }
|
||||
|
||||
.activity-tags {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
flex-wrap: wrap;
|
||||
gap: 4px;
|
||||
.tag {
|
||||
padding: 2px 4px;
|
||||
font-size: 11px;
|
||||
color: #fff;
|
||||
border-radius: 2px;
|
||||
&.kj { background: #1890ff; }
|
||||
&.pt { background: #52c41a; }
|
||||
&.ms { background: #f5222d; }
|
||||
}
|
||||
}
|
||||
|
||||
.mock-switch {
|
||||
width: 50px;
|
||||
height: 20px;
|
||||
background: #dbdbdb;
|
||||
border-radius: 10px;
|
||||
position: relative;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding: 0 4px;
|
||||
&.on {
|
||||
background: #1890ff;
|
||||
.switch-dot { left: 32px; }
|
||||
.switch-txt { left: 6px; }
|
||||
}
|
||||
&:not(.on) {
|
||||
.switch-txt { right: 6px; }
|
||||
.switch-dot { left: 2px; }
|
||||
}
|
||||
.switch-txt {
|
||||
position: absolute;
|
||||
font-size: 10px;
|
||||
color: #fff;
|
||||
}
|
||||
.switch-dot {
|
||||
position: absolute;
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
background: #fff;
|
||||
border-radius: 50%;
|
||||
transition: left 0.2s;
|
||||
}
|
||||
}
|
||||
|
||||
.op-link {
|
||||
font-size: 13px;
|
||||
color: #1890ff;
|
||||
cursor: pointer;
|
||||
&.danger { color: #ff4d4f; }
|
||||
}
|
||||
.op-divider { color: #e8e8e8; font-size: 12px; margin: 0 4px; }
|
||||
|
||||
.more-dropdown {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
.arrow { font-size: 10px; color: #1890ff; margin-left: 2px; }
|
||||
}
|
||||
|
||||
.pagination-row {
|
||||
padding: 24px;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
justify-content: flex-end;
|
||||
align-items: center;
|
||||
gap: 16px;
|
||||
.total { font-size: 13px; color: #606266; }
|
||||
}
|
||||
|
||||
.page-ctrl {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
gap: 8px;
|
||||
.page-num, .page-btn {
|
||||
width: 32px;
|
||||
height: 32px;
|
||||
border: 1px solid #dcdfe6;
|
||||
border-radius: 4px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
font-size: 13px;
|
||||
color: #606266;
|
||||
&.active { background: #1890ff; color: #fff; border-color: #1890ff; }
|
||||
&.disabled { color: #c0c4cc; background: #f5f7fa; }
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -0,0 +1,68 @@
|
||||
<template>
|
||||
<view class="member-price-page">
|
||||
<view class="page-header">
|
||||
<view class="back-link" @click="goBack">
|
||||
<text class="arrow">{"<"}</text>
|
||||
<text class="back-txt">返回</text>
|
||||
</view>
|
||||
<text class="header-title">会员价管理</text>
|
||||
</view>
|
||||
|
||||
<view class="content-card">
|
||||
<view class="product-info">
|
||||
<image class="p-img" src="https://img1.baidu.com/it/u=254065646,3100346083&fm=253&fmt=auto&app=138&f=JPEG?w=500&h=500" mode="aspectFill" />
|
||||
<text class="p-name">UR2024夏季新款女装复古纯欲氛围感一字肩短款T恤衫</text>
|
||||
</view>
|
||||
|
||||
<view class="price-table">
|
||||
<view class="th-row">
|
||||
<view class="th flex-2"><text>规格名称</text></view>
|
||||
<view class="th flex-1"><text>售价</text></view>
|
||||
<view class="th flex-1"><text>普通会员价</text></view>
|
||||
<view class="th flex-1"><text>黄金会员价</text></view>
|
||||
<view class="th flex-1"><text>铂金会员价</text></view>
|
||||
</view>
|
||||
<view class="tr-row">
|
||||
<view class="td flex-2"><text>XL,卡其</text></view>
|
||||
<view class="td flex-1"><text>¥99.00</text></view>
|
||||
<view class="td flex-1"><input class="price-input" value="89.00" /></view>
|
||||
<view class="td flex-1"><input class="price-input" value="79.00" /></view>
|
||||
<view class="td flex-1"><input class="price-input" value="69.00" /></view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class="footer-btns">
|
||||
<button class="btn-save">保存设置</button>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script setup lang="uts">
|
||||
import { openRoute } from '@/layouts/admin/store/adminNavStore.uts'
|
||||
|
||||
function goBack() {
|
||||
openRoute('product_productList')
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.member-price-page { padding: 20px; background: #f5f7f9; min-height: 100vh; }
|
||||
.page-header { display: flex; flex-direction: row; align-items: center; gap: 16px; margin-bottom: 20px;
|
||||
.back-link { display: flex; flex-direction: row; align-items: center; gap: 4px; color: #666; cursor: pointer; }
|
||||
.header-title { font-size: 16px; font-weight: bold; color: #333; }
|
||||
}
|
||||
.content-card { background: #fff; border-radius: 4px; padding: 24px; }
|
||||
.product-info { display: flex; flex-direction: row; align-items: center; gap: 16px; margin-bottom: 30px;
|
||||
.p-img { width: 64px; height: 64px; border-radius: 4px; }
|
||||
.p-name { font-size: 15px; font-weight: bold; color: #333; }
|
||||
}
|
||||
.price-table { border: 1px solid #f0f0f0; border-radius: 4px; }
|
||||
.th-row { display: flex; flex-direction: row; background: #f8f9fa; border-bottom: 1px solid #f0f0f0; }
|
||||
.th { padding: 12px; font-size: 14px; font-weight: 500; color: #333; text-align: center; }
|
||||
.tr-row { display: flex; flex-direction: row; border-bottom: 1px solid #f0f0f0; &:last-child { border-bottom: none; } }
|
||||
.td { padding: 16px 12px; font-size: 14px; color: #666; text-align: center; display: flex; align-items: center; justify-content: center; }
|
||||
.flex-1 { flex: 1; } .flex-2 { flex: 2; }
|
||||
.price-input { border: 1px solid #dcdfe6; border-radius: 4px; height: 32px; padding: 0 8px; text-align: center; width: 80%; font-size: 13px; }
|
||||
.footer-btns { margin-top: 40px; display: flex; justify-content: center; .btn-save { background: #1890ff; color: #fff; border: none; padding: 0 32px; height: 40px; border-radius: 4px; } }
|
||||
</style>
|
||||
@@ -1,26 +1,568 @@
|
||||
<template>
|
||||
<AdminLayout :currentPage="currentPage">
|
||||
<view class="page">
|
||||
<view class="header">
|
||||
<text class="title">{{ title }}</text>
|
||||
<text class="sub-title">分析商品销售数据和趋势</text>
|
||||
<view class="product-statistic-page">
|
||||
<!-- 商品概况头部 -->
|
||||
<view class="page-header-row">
|
||||
<view class="title-wrap">
|
||||
<text class="page-title">商品概况</text>
|
||||
<view class="info-icon">?</view>
|
||||
</view>
|
||||
<view class="header-right">
|
||||
<view class="date-picker-wrap">
|
||||
<text class="calendar-emoji">📅</text>
|
||||
<text class="date-range">2026/01/04 - 2026/02/02</text>
|
||||
</view>
|
||||
<button class="btn-query">查询</button>
|
||||
<button class="btn-export">导出</button>
|
||||
</view>
|
||||
</view>
|
||||
</AdminLayout>
|
||||
|
||||
<!-- 统计指标网格 -->
|
||||
<view class="stat-grid">
|
||||
<view v-for="(item, index) in statItems" :key="index" class="stat-card">
|
||||
<view class="stat-main">
|
||||
<view class="icon-box" :style="{ backgroundColor: item.bgColor }">
|
||||
<text class="stat-emoji">{{ item.emoji }}</text>
|
||||
</view>
|
||||
<view class="stat-content">
|
||||
<text class="stat-label">{{ item.label }}</text>
|
||||
<text class="stat-value">{{ item.value }}</text>
|
||||
<view class="stat-compare">
|
||||
<text class="compare-label">坏比增长:</text>
|
||||
<text class="compare-val" :class="item.trendClass">
|
||||
{{ item.compare }}
|
||||
<text v-if="item.trend === 'up'" class="arrow">▲</text>
|
||||
<text v-else-if="item.trend === 'down'" class="arrow">▼</text>
|
||||
<text v-else>-</text>
|
||||
</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 图表卡片 -->
|
||||
<view class="chart-card">
|
||||
<view class="chart-header">
|
||||
<view class="legend-wrap">
|
||||
<view class="legend-item"><view class="dot purple"></view><text>商品浏览量</text></view>
|
||||
<view class="legend-item"><view class="dot orange"></view><text>商品访客量</text></view>
|
||||
<view class="legend-item"><view class="dot blue"></view><text>支付金额</text></view>
|
||||
<view class="legend-item"><view class="dot green"></view><text>退款金额</text></view>
|
||||
</view>
|
||||
<view class="download-icon">
|
||||
<text class="download-emoji">📥</text>
|
||||
</view>
|
||||
</view>
|
||||
<view class="chart-main">
|
||||
<EChartsView v-if="chartOption != null" :option="chartOption" class="main-chart" />
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 商品排行 -->
|
||||
<view class="ranking-card">
|
||||
<view class="ranking-header">
|
||||
<text class="ranking-title">商品排行</text>
|
||||
<view class="ranking-filters">
|
||||
<view class="mock-select-wrap">
|
||||
<text class="select-val">浏览量</text>
|
||||
<text class="select-arrow">▼</text>
|
||||
</view>
|
||||
<view class="date-picker-wrap">
|
||||
<text class="calendar-emoji">📅</text>
|
||||
<text class="date-range">2026/01/04 - 2026/02/02</text>
|
||||
</view>
|
||||
<button class="btn-query small">查询</button>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class="ranking-table">
|
||||
<view class="table-header">
|
||||
<text class="th col-id">ID</text>
|
||||
<text class="th col-img">商品图片</text>
|
||||
<text class="th col-name">商品名称</text>
|
||||
<text class="th col-num">浏览量</text>
|
||||
<text class="th col-num">访客数</text>
|
||||
<text class="th col-num">加购件数</text>
|
||||
<text class="th col-num">下单件数</text>
|
||||
<text class="th col-num">支付件数</text>
|
||||
<text class="th col-num">支付金额</text>
|
||||
<text class="th col-num">收藏数</text>
|
||||
<text class="th col-num wide">访客-支付转化率(%)</text>
|
||||
</view>
|
||||
<view v-for="(item, index) in rankingList" :key="index" class="table-row">
|
||||
<text class="td col-id">{{ item.id }}</text>
|
||||
<view class="td col-img">
|
||||
<image class="product-img" :src="item.image" mode="aspectFill" />
|
||||
</view>
|
||||
<view class="td col-name">
|
||||
<text class="product-name-txt">{{ item.name }}</text>
|
||||
</view>
|
||||
<text class="td col-num">{{ item.views }}</text>
|
||||
<text class="td col-num">{{ item.visitors }}</text>
|
||||
<text class="td col-num">{{ item.cartCount }}</text>
|
||||
<text class="td col-num">{{ item.orderCount }}</text>
|
||||
<text class="td col-num">{{ item.payCount }}</text>
|
||||
<text class="td col-num">{{ item.payAmount }}</text>
|
||||
<text class="td col-num">{{ item.favCount }}</text>
|
||||
<text class="td col-num wide">{{ item.conversion }}%</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script setup lang="uts">
|
||||
import { ref } from 'vue'
|
||||
import AdminLayout from '@/layouts/admin/AdminLayout.uvue'
|
||||
const currentPage = ref<string>('product-statistics-group')
|
||||
const title = ref<string>('商品统计')
|
||||
import { ref, onMounted } from 'vue'
|
||||
import EChartsView from '@/uni_modules/charts/EChartsView.vue'
|
||||
|
||||
const statItems = ref([
|
||||
{ label: '商品浏览量', value: '7576', compare: '0.93%', trend: 'up', trendClass: 'up-red', bgColor: '#e6f7ff', emoji: '👁️' },
|
||||
{ label: '商品访客量', value: '765', compare: '0.79%', trend: 'up', trendClass: 'up-red', bgColor: '#f6ffed', emoji: '👤' },
|
||||
{ label: '支付件数', value: '322', compare: '-49.52%', trend: 'down', trendClass: 'down-green', bgColor: '#fff7e6', emoji: '🛍️' },
|
||||
{ label: '支付金额', value: '443254.62', compare: '-63.62%', trend: 'down', trendClass: 'down-green', bgColor: '#f9f0ff', emoji: '💰' },
|
||||
{ label: '退款件数', value: '0', compare: '0.00%', trend: 'none', trendClass: 'none-gray', bgColor: '#e6f7ff', emoji: '🔄' },
|
||||
{ label: '退款金额', value: '0', compare: '0.00%', trend: 'none', trendClass: 'none-gray', bgColor: '#f6ffed', emoji: '💴' }
|
||||
])
|
||||
|
||||
const rankingList = ref([
|
||||
{
|
||||
id: 963,
|
||||
image: 'https://img1.baidu.com/it/u=254065646,3100346083&fm=253&fmt=auto&app=138&f=JPEG?w=500&h=500',
|
||||
name: 'UR2024夏季新款女装复古纯欲氛围感一字肩短款T恤衫UWG440060',
|
||||
views: 1200,
|
||||
visitors: 246,
|
||||
cartCount: 74,
|
||||
orderCount: 214,
|
||||
payCount: 180,
|
||||
payAmount: '11877.49',
|
||||
favCount: 13,
|
||||
conversion: 18
|
||||
},
|
||||
{
|
||||
id: 116,
|
||||
image: 'https://img2.baidu.com/it/u=3775079632,546700868&fm=253&fmt=auto&app=138&f=JPEG?w=500&h=500',
|
||||
name: '爱奇艺智能 奇遇LT01 投影仪 家用卧室超高清手机便携投影机 (4K超清 支持侧投 手机同屏 华为一碰即投)',
|
||||
views: 959,
|
||||
visitors: 376,
|
||||
cartCount: 1,
|
||||
orderCount: 60,
|
||||
payCount: 29,
|
||||
payAmount: '26.00',
|
||||
favCount: 6,
|
||||
conversion: 7
|
||||
},
|
||||
{
|
||||
id: 48,
|
||||
image: 'https://img0.baidu.com/it/u=1762118431,3101886131&fm=253&fmt=auto&app=138&f=JPEG?w=500&h=500',
|
||||
name: '阿迪达斯官网 adidas BBALL CAP COT 男女训练运动帽子FQ5270 传奇墨水蓝/传奇墨水蓝/白 XL',
|
||||
views: 758,
|
||||
visitors: 207,
|
||||
cartCount: 63,
|
||||
orderCount: 67,
|
||||
payCount: 17,
|
||||
payAmount: '1409.30',
|
||||
favCount: 4,
|
||||
conversion: 7
|
||||
},
|
||||
{
|
||||
id: 108,
|
||||
image: 'https://img2.baidu.com/it/u=3033501986,2204481084&fm=253&fmt=auto&app=138&f=JPEG?w=569&h=500',
|
||||
name: 'FOMIX 蛋壳椅 进口头层牛皮橙色单人沙发椅Egg chair设计师师单椅单沙头层牛皮/单椅',
|
||||
views: 730,
|
||||
visitors: 216,
|
||||
cartCount: 26999,
|
||||
orderCount: 327,
|
||||
payCount: 14,
|
||||
payAmount: '66197.00',
|
||||
favCount: 4,
|
||||
conversion: 6
|
||||
}
|
||||
])
|
||||
|
||||
const chartOption = ref<any>({})
|
||||
|
||||
onMounted(() => {
|
||||
setTimeout(() => {
|
||||
initChart()
|
||||
}, 300)
|
||||
})
|
||||
|
||||
function toPlainObject(obj: any): any {
|
||||
if (obj == null) return null
|
||||
if (typeof obj !== 'object') return obj
|
||||
if (Array.isArray(obj)) {
|
||||
return obj.map((item: any) : any => toPlainObject(item))
|
||||
}
|
||||
const plain: any = {}
|
||||
const keys = Object.keys(obj)
|
||||
for (let i = 0; i < keys.length; i++) {
|
||||
const key = keys[i]
|
||||
const value = obj[key]
|
||||
if (typeof value === 'function' || key.startsWith('_') || key === 'toJSON') {
|
||||
continue
|
||||
}
|
||||
if (value != null && typeof value === 'object') {
|
||||
plain[key] = toPlainObject(value)
|
||||
} else {
|
||||
plain[key] = value
|
||||
}
|
||||
}
|
||||
return plain
|
||||
}
|
||||
|
||||
function initChart() {
|
||||
const dates = [
|
||||
'01-04', '01-05', '01-06', '01-07', '01-08', '01-09', '01-10', '01-11', '01-12', '01-13',
|
||||
'01-14', '01-15', '01-16', '01-17', '01-18', '01-19', '01-20', '01-21', '01-22', '01-23',
|
||||
'01-24', '01-25', '01-26', '01-27', '01-28', '01-29', '01-30', '01-31', '02-01', '02-02'
|
||||
]
|
||||
|
||||
const option = {
|
||||
tooltip: {
|
||||
trigger: 'axis',
|
||||
backgroundColor: 'rgba(50, 50, 50, 0.7)',
|
||||
padding: [10, 15],
|
||||
textStyle: { color: '#fff' },
|
||||
formatter: (params: any[]) : string => {
|
||||
let res = `<div style="font-size:12px; color:#ccc; margin-bottom:5px;">${params[0].name}</div>`
|
||||
params.forEach(p => {
|
||||
res += `<div style="display:flex; align-items:center;">
|
||||
<div style="width:8px; height:8px; border-radius:50%; background:${p.color}; margin-right:8px;"></div>
|
||||
<span>${p.seriesName}: ${p.value}</span>
|
||||
</div>`
|
||||
})
|
||||
return res
|
||||
}
|
||||
},
|
||||
grid: {
|
||||
left: '3%',
|
||||
right: '4%',
|
||||
bottom: '5%',
|
||||
top: '10%',
|
||||
containLabel: true
|
||||
},
|
||||
xAxis: {
|
||||
type: 'category',
|
||||
data: dates,
|
||||
axisLine: { lineStyle: { color: '#f0f0f0' } },
|
||||
axisLabel: { color: '#8c8c8c', fontSize: 11 },
|
||||
axisTick: { show: false }
|
||||
},
|
||||
yAxis: [
|
||||
{
|
||||
type: 'value',
|
||||
name: '金额',
|
||||
nameTextStyle: { color: '#8c8c8c', padding: [0, 30, 0, 0] },
|
||||
splitLine: { lineStyle: { type: 'dashed', color: '#f0f0f0' } },
|
||||
axisLabel: { color: '#8c8c8c' }
|
||||
},
|
||||
{
|
||||
type: 'value',
|
||||
name: '数量',
|
||||
nameTextStyle: { color: '#8c8c8c', padding: [0, 0, 0, 30] },
|
||||
splitLine: { show: false },
|
||||
axisLabel: { color: '#8c8c8c' }
|
||||
}
|
||||
],
|
||||
series: [
|
||||
{
|
||||
name: '商品浏览量',
|
||||
type: 'line',
|
||||
yAxisIndex: 1,
|
||||
smooth: true,
|
||||
showSymbol: false,
|
||||
itemStyle: { color: '#b37feb' },
|
||||
lineStyle: { width: 2 },
|
||||
data: [90, 110, 115, 100, 95, 80, 60, 40, 70, 85, 75, 65, 70, 80, 100, 120, 110, 90, 60, 95, 115, 110, 85, 50, 45, 55, 75]
|
||||
},
|
||||
{
|
||||
name: '商品访客量',
|
||||
type: 'line',
|
||||
yAxisIndex: 1,
|
||||
smooth: true,
|
||||
showSymbol: false,
|
||||
itemStyle: { color: '#ffbb96' },
|
||||
lineStyle: { width: 2 },
|
||||
data: [15, 12, 10, 8, 11, 14, 13, 8, 9, 11, 10, 15, 12, 11, 9, 12, 14, 15, 11, 10, 13, 15, 11, 8, 12, 10, 14]
|
||||
},
|
||||
{
|
||||
name: '支付金额',
|
||||
type: 'bar',
|
||||
barWidth: '25%',
|
||||
itemStyle: { color: '#1890ff' },
|
||||
data: [10, 5, 8, 0, 145, 15, 5, 0, 0, 0, 0, 5, 30, 0, 15, 20, 100, 20, 25, 5, 1, 3, 70, 5, 10, 5, 15, 10]
|
||||
},
|
||||
{
|
||||
name: '退款金额',
|
||||
type: 'bar',
|
||||
barWidth: '25%',
|
||||
itemStyle: { color: '#52c41a' },
|
||||
data: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
|
||||
}
|
||||
],
|
||||
markLine: {
|
||||
silent: true,
|
||||
symbol: ['none', 'none'],
|
||||
label: { show: false },
|
||||
lineStyle: { color: '#bfbfbf', type: 'dashed' },
|
||||
data: [{ yAxis: 145853.16 }]
|
||||
}
|
||||
}
|
||||
|
||||
chartOption.value = toPlainObject(option)
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
@import '@/uni.scss';
|
||||
.page { padding: $space-lg; }
|
||||
.header { padding: $space-lg; border-radius: $radius; background: $background-primary; box-shadow: $shadow-xs; }
|
||||
.title { font-size: $font-size-lg; font-weight: $font-weight-bold; color: $text-primary; }
|
||||
.sub-title { margin-top: $space-xs; font-size: $font-size-md; color: $text-secondary; }
|
||||
.product-statistic-page {
|
||||
padding: 16px;
|
||||
background-color: #f0f2f5;
|
||||
min-height: 100vh;
|
||||
}
|
||||
|
||||
.page-header-row {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
.title-wrap {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
}
|
||||
|
||||
.page-title { font-size: 16px; font-weight: bold; color: #333; }
|
||||
|
||||
.info-icon {
|
||||
width: 14px; height: 14px;
|
||||
border-radius: 50%; border: 1px solid #999;
|
||||
color: #999; font-size: 10px;
|
||||
display: flex; align-items: center; justify-content: center;
|
||||
}
|
||||
|
||||
.header-right {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
gap: 12px;
|
||||
}
|
||||
|
||||
.date-picker-wrap {
|
||||
background: #fff;
|
||||
border: 1px solid #d9d9d9;
|
||||
padding: 6px 12px;
|
||||
border-radius: 4px;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
}
|
||||
.calendar-emoji { font-size: 14px; }
|
||||
.date-range { font-size: 14px; color: #595959; }
|
||||
|
||||
.btn-query { background: #1890ff; color: #fff; font-size: 14px; height: 32px; padding: 0 15px; border-radius: 4px; border: none; }
|
||||
.btn-export { background: #1890ff; color: #fff; font-size: 14px; height: 32px; padding: 0 15px; border-radius: 4px; border: none; }
|
||||
|
||||
.stat-grid {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
flex-wrap: wrap;
|
||||
gap: 16px;
|
||||
margin-bottom: 16px;
|
||||
}
|
||||
|
||||
.stat-card {
|
||||
width: calc(33.33% - 11px);
|
||||
background: #fff;
|
||||
border-radius: 8px;
|
||||
padding: 20px;
|
||||
}
|
||||
|
||||
.stat-main {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
gap: 16px;
|
||||
}
|
||||
|
||||
.icon-box {
|
||||
width: 48px; height: 48px;
|
||||
border-radius: 50%;
|
||||
display: flex; align-items: center; justify-content: center;
|
||||
}
|
||||
|
||||
.stat-emoji { font-size: 24px; }
|
||||
|
||||
.stat-content {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.stat-label { font-size: 13px; color: #8c8c8c; margin-bottom: 4px; }
|
||||
.stat-value { font-size: 24px; font-weight: bold; color: #262626; margin-bottom: 4px; }
|
||||
|
||||
.stat-compare {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
font-size: 12px;
|
||||
}
|
||||
.compare-label { color: #8c8c8c; }
|
||||
.up-red { color: #ff4d4f; }
|
||||
.down-green { color: #52c41a; }
|
||||
.none-gray { color: #8c8c8c; }
|
||||
.arrow { font-size: 10px; margin-left: 2px; }
|
||||
|
||||
.chart-card {
|
||||
background: #fff;
|
||||
border-radius: 8px;
|
||||
padding: 24px;
|
||||
}
|
||||
|
||||
.chart-header {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
position: relative;
|
||||
margin-bottom: 30px;
|
||||
}
|
||||
|
||||
.legend-wrap {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
gap: 24px;
|
||||
}
|
||||
|
||||
.legend-item {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
text { font-size: 12px; color: #8c8c8c; }
|
||||
}
|
||||
|
||||
.dot { width: 10px; height: 10px; border-radius: 2px; }
|
||||
.purple { background-color: #b37feb; }
|
||||
.orange { background-color: #ffbb96; }
|
||||
.blue { background-color: #1890ff; }
|
||||
.green { background-color: #52c41a; }
|
||||
|
||||
.download-icon {
|
||||
position: absolute;
|
||||
right: 0;
|
||||
}
|
||||
.download-emoji { font-size: 18px; opacity: 0.6; }
|
||||
|
||||
.chart-main {
|
||||
height: 400px;
|
||||
width: 100%;
|
||||
}
|
||||
.main-chart { width: 100%; height: 100%; }
|
||||
|
||||
/* 商品排行 */
|
||||
.ranking-card {
|
||||
background: #fff;
|
||||
border-radius: 8px;
|
||||
padding: 24px;
|
||||
margin-top: 16px;
|
||||
margin-bottom: 24px;
|
||||
}
|
||||
|
||||
.ranking-header {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
.ranking-title { font-size: 16px; font-weight: bold; color: #333; }
|
||||
|
||||
.ranking-filters {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
gap: 12px;
|
||||
}
|
||||
|
||||
.mock-select-wrap {
|
||||
border: 1px solid #d9d9d9;
|
||||
border-radius: 4px;
|
||||
padding: 4px 12px;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
min-width: 120px;
|
||||
}
|
||||
.select-val { font-size: 14px; color: #595959; flex: 1; }
|
||||
.select-arrow { font-size: 10px; color: #bfbfbf; }
|
||||
|
||||
.btn-query.small { height: 32px; font-size: 13px; margin: 0; }
|
||||
|
||||
.ranking-table {
|
||||
border: 1px solid #f0f0f0;
|
||||
border-radius: 4px;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.table-header {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
background-color: #e6f7ff;
|
||||
border-bottom: 1px solid #f0f0f0;
|
||||
}
|
||||
|
||||
.th {
|
||||
padding: 12px 8px;
|
||||
font-size: 13px;
|
||||
font-weight: 500;
|
||||
color: #595959;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.table-row {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
border-bottom: 1px solid #f0f0f0;
|
||||
align-items: stretch;
|
||||
}
|
||||
.table-row:last-child { border-bottom: none; }
|
||||
|
||||
.td {
|
||||
padding: 16px 8px;
|
||||
font-size: 13px;
|
||||
color: #262626;
|
||||
text-align: center;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
/* 列宽度配置 */
|
||||
.col-id { width: 60px; }
|
||||
.col-img { width: 100px; }
|
||||
.col-name { flex: 1; text-align: left; justify-content: flex-start; }
|
||||
.col-num { width: 80px; }
|
||||
.col-num.wide { width: 120px; }
|
||||
|
||||
.product-img {
|
||||
width: 48px;
|
||||
height: 48px;
|
||||
background: #f5f5f5;
|
||||
border-radius: 4px;
|
||||
}
|
||||
|
||||
.product-name-txt {
|
||||
font-size: 13px;
|
||||
line-height: 1.5;
|
||||
color: #262626;
|
||||
}
|
||||
</style>
|
||||
|
||||
|
||||
@@ -1,15 +1,95 @@
|
||||
<template>
|
||||
<view class="page-container">
|
||||
<view class="page-header">
|
||||
<text class="page-title">商品评论</text>
|
||||
<text class="page-subtitle">Component: ProductReply</text>
|
||||
<view class="product-reply-page">
|
||||
<!-- 1. 搜索筛选 -->
|
||||
<view class="search-card">
|
||||
<view class="search-row">
|
||||
<view class="search-item">
|
||||
<text class="label">评价时间:</text>
|
||||
<view class="mock-date-range">
|
||||
<text class="emoji">📅</text>
|
||||
<text class="txt">开始日期 - 结束日期</text>
|
||||
</view>
|
||||
</view>
|
||||
<view class="search-item">
|
||||
<text class="label">评价状态:</text>
|
||||
<view class="mock-select"><text>请选择</text><text class="arrow">▼</text></view>
|
||||
</view>
|
||||
<view class="search-item">
|
||||
<text class="label">审核状态:</text>
|
||||
<view class="mock-select"><text>请选择</text><text class="arrow">▼</text></view>
|
||||
</view>
|
||||
</view>
|
||||
<view class="search-row mt-16">
|
||||
<view class="search-item">
|
||||
<text class="label">商品信息:</text>
|
||||
<input class="mock-input" placeholder="请输入商品信息" />
|
||||
</view>
|
||||
<view class="search-item">
|
||||
<text class="label">用户名称:</text>
|
||||
<input class="mock-input" placeholder="请输入" />
|
||||
</view>
|
||||
<button class="btn-primary">查询</button>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class="page-content">
|
||||
<view class="placeholder-card">
|
||||
<text class="placeholder-title">页面占位</text>
|
||||
<text class="placeholder-desc">该功能模块正在开发中</text>
|
||||
<text class="placeholder-info">当前采用 CRMEB 路由体系 1:1 映射</text>
|
||||
|
||||
<!-- 2. 操作行 -->
|
||||
<view class="action-bar">
|
||||
<button class="btn-primary">添加自评</button>
|
||||
<button class="btn-white">批量审核</button>
|
||||
</view>
|
||||
|
||||
<!-- 3. 数据表格 -->
|
||||
<view class="list-card">
|
||||
<view class="table-v5">
|
||||
<view class="th-row">
|
||||
<view class="th col-check"><text>□</text></view>
|
||||
<view class="th col-id"><text>评论ID</text></view>
|
||||
<view class="th col-product"><text>商品信息</text></view>
|
||||
<view class="th col-spec"><text>规格</text></view>
|
||||
<view class="th col-user"><text>用户名称</text></view>
|
||||
<view class="th col-score"><text>评分</text></view>
|
||||
<view class="th col-content"><text>评价内容</text></view>
|
||||
<view class="th col-reply"><text>回复内容</text></view>
|
||||
<view class="th col-status"><text>审核状态</text></view>
|
||||
<view class="th col-time"><text>评价时间</text></view>
|
||||
<view class="th col-op"><text>操作</text></view>
|
||||
</view>
|
||||
|
||||
<view v-for="item in replyList" :key="item.id" class="tr-row">
|
||||
<view class="td col-check"><text>□</text></view>
|
||||
<view class="td col-id"><text>{{ item.id }}</text></view>
|
||||
<view class="td col-product">
|
||||
<image class="p-img" :src="item.image" mode="aspectFill" />
|
||||
<text class="p-name-txt">{{ item.productName }}</text>
|
||||
</view>
|
||||
<view class="td col-spec"><text>{{ item.spec }}</text></view>
|
||||
<view class="td col-user"><text>{{ item.username }}</text></view>
|
||||
<view class="td col-score"><text>{{ item.score }}</text></view>
|
||||
<view class="td col-content"><text class="blue-link">{{ item.content }}</text></view>
|
||||
<view class="td col-reply"><text>{{ item.reply || '无' }}</text></view>
|
||||
<view class="td col-status">
|
||||
<text class="status-tag" :class="item.status === 1 ? 'pass' : 'wait'">
|
||||
{{ item.status === 1 ? '通过' : '待审核' }}
|
||||
</text>
|
||||
</view>
|
||||
<view class="td col-time"><text>{{ item.time }}</text></view>
|
||||
<view class="td col-op">
|
||||
<text class="op-link">通过</text>
|
||||
<text class="op-link">驳回</text>
|
||||
<text class="op-link">回复</text>
|
||||
<text class="op-link red">删除</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 分页 -->
|
||||
<view class="pagination-row">
|
||||
<text class="total">共 {{ replyList.length }} 条</text>
|
||||
<view class="page-ctrl">
|
||||
<text class="page-btn disabled">{"<"}</text>
|
||||
<text class="page-num active">1</text>
|
||||
<text class="page-btn">{">"}</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
@@ -18,64 +98,169 @@
|
||||
<script setup lang="uts">
|
||||
import { ref } from 'vue'
|
||||
|
||||
// TODO: 实现 商品评论 的具体功能
|
||||
const loading = ref<boolean>(false)
|
||||
const replyList = ref([
|
||||
{
|
||||
id: 1069,
|
||||
image: 'https://img1.baidu.com/it/u=254065646,3100346083&fm=253&fmt=auto&app=138&f=JPEG?w=500&h=500',
|
||||
productName: 'UR2024夏季新款女装复古纯欲氛围感一字肩短款T恤衫UWG440060',
|
||||
spec: 'XL,卡其',
|
||||
username: 'demo998',
|
||||
score: 3.5,
|
||||
content: '22',
|
||||
reply: '',
|
||||
status: 0,
|
||||
time: '2025-02-19 14:56:43'
|
||||
},
|
||||
{
|
||||
id: 1059,
|
||||
image: 'https://img1.baidu.com/it/u=254065646,3100346083&fm=253&fmt=auto&app=138&f=JPEG?w=500&h=500',
|
||||
productName: 'UR2024夏季新款女装复古纯欲氛围感一字肩短款T恤衫UWG440060',
|
||||
spec: 'XL,卡其',
|
||||
username: '你好呀',
|
||||
score: 3.5,
|
||||
content: '的',
|
||||
reply: '',
|
||||
status: 0,
|
||||
time: '2025-01-07 15:35:36'
|
||||
},
|
||||
{
|
||||
id: 980,
|
||||
image: 'https://img1.baidu.com/it/u=254065646,3100346083&fm=253&fmt=auto&app=138&f=JPEG?w=500&h=500',
|
||||
productName: 'UR2024夏季新款女装复古纯欲氛围感一字肩短款T恤衫UWG440060',
|
||||
spec: 'XL,卡其',
|
||||
username: 'wx209638',
|
||||
score: 5,
|
||||
content: '好',
|
||||
reply: '',
|
||||
status: 1,
|
||||
time: '2024-09-12 14:20:12'
|
||||
}
|
||||
])
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.page-container {
|
||||
.product-reply-page {
|
||||
padding: 20px;
|
||||
background-color: #f5f7f9;
|
||||
min-height: 100vh;
|
||||
background: #f5f5f5;
|
||||
}
|
||||
|
||||
.page-header {
|
||||
margin-bottom: 20px;
|
||||
.search-card {
|
||||
background: #fff;
|
||||
padding: 24px;
|
||||
border-radius: 4px;
|
||||
margin-bottom: 16px;
|
||||
}
|
||||
|
||||
.page-title {
|
||||
display: block;
|
||||
font-size: 24px;
|
||||
font-weight: 600;
|
||||
color: #333;
|
||||
margin-bottom: 8px;
|
||||
.search-row {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
gap: 24px;
|
||||
}
|
||||
.mt-16 { margin-top: 16px; }
|
||||
|
||||
.search-item {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
.label { font-size: 14px; color: #606266; width: 80px; text-align: right; }
|
||||
}
|
||||
|
||||
.page-subtitle {
|
||||
display: block;
|
||||
font-size: 14px;
|
||||
color: #999;
|
||||
.mock-date-range {
|
||||
width: 280px; height: 32px; border: 1px solid #dcdfe6; border-radius: 4px;
|
||||
display: flex; flex-direction: row; align-items: center; padding: 0 12px; gap: 8px;
|
||||
.emoji { font-size: 14px; }
|
||||
.txt { font-size: 13px; color: #c0c4cc; }
|
||||
}
|
||||
|
||||
.page-content {
|
||||
.mock-select {
|
||||
width: 160px; height: 32px; border: 1px solid #dcdfe6; border-radius: 4px;
|
||||
display: flex; flex-direction: row; align-items: center; justify-content: space-between;
|
||||
padding: 0 12px; font-size: 13px; color: #606266;
|
||||
.arrow { font-size: 10px; color: #c0c4cc; }
|
||||
}
|
||||
|
||||
.mock-input {
|
||||
width: 200px; height: 32px; border: 1px solid #dcdfe6; border-radius: 4px; padding: 0 12px; font-size: 13px;
|
||||
}
|
||||
|
||||
.btn-primary { background: #1890ff; color: #fff; height: 32px; padding: 0 16px; border-radius: 4px; font-size: 14px; border: none; }
|
||||
.btn-white { background: #fff; color: #606266; height: 32px; padding: 0 16px; border-radius: 4px; font-size: 14px; border: 1px solid #dcdfe6; }
|
||||
|
||||
.action-bar {
|
||||
margin-bottom: 16px;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
gap: 12px;
|
||||
}
|
||||
|
||||
.list-card {
|
||||
background: #fff;
|
||||
border-radius: 4px;
|
||||
padding: 24px;
|
||||
}
|
||||
|
||||
.placeholder-card {
|
||||
text-align: center;
|
||||
padding: 60px 20px;
|
||||
.table-v5 { width: 100%; }
|
||||
|
||||
.th-row {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
background-color: #f8f9fa;
|
||||
border-bottom: 1px solid #e8e8e8;
|
||||
}
|
||||
|
||||
.placeholder-title {
|
||||
display: block;
|
||||
font-size: 18px;
|
||||
font-weight: 600;
|
||||
color: #666;
|
||||
margin-bottom: 12px;
|
||||
.th {
|
||||
padding: 12px 8px; font-size: 13px; font-weight: 500; color: #333;
|
||||
display: flex; align-items: center; justify-content: center;
|
||||
}
|
||||
|
||||
.placeholder-desc {
|
||||
display: block;
|
||||
font-size: 14px;
|
||||
color: #999;
|
||||
margin-bottom: 8px;
|
||||
.tr-row {
|
||||
display: flex; flex-direction: row; border-bottom: 1px solid #f0f0f0;
|
||||
&:hover { background-color: #fafafa; }
|
||||
}
|
||||
|
||||
.placeholder-info {
|
||||
display: block;
|
||||
font-size: 12px;
|
||||
color: #1890ff;
|
||||
.td {
|
||||
padding: 12px 8px; font-size: 13px; color: #606266;
|
||||
display: flex; align-items: center; justify-content: center;
|
||||
}
|
||||
|
||||
.col-check { width: 50px; }
|
||||
.col-id { width: 80px; }
|
||||
.col-product { flex: 1.5; justify-content: flex-start; gap: 12px; }
|
||||
.col-spec { width: 100px; }
|
||||
.col-user { width: 120px; }
|
||||
.col-score { width: 80px; }
|
||||
.col-content { flex: 1; }
|
||||
.col-reply { flex: 1; }
|
||||
.col-status { width: 100px; }
|
||||
.col-time { width: 160px; }
|
||||
.col-op { width: 180px; }
|
||||
|
||||
.p-img { width: 40px; height: 40px; border-radius: 4px; }
|
||||
.p-name-txt { font-size: 13px; line-height: 1.4; color: #1890ff; }
|
||||
|
||||
.blue-link { color: #1890ff; }
|
||||
|
||||
.status-tag {
|
||||
padding: 2px 8px; border-radius: 2px; font-size: 12px;
|
||||
&.pass { background: rgba(82, 196, 26, 0.1); color: #52c41a; }
|
||||
&.wait { background: rgba(250, 173, 20, 0.1); color: #faad14; }
|
||||
}
|
||||
|
||||
.op-link { font-size: 13px; color: #1890ff; margin: 0 4px; cursor: pointer; &.red { color: #f5222d; } }
|
||||
|
||||
.pagination-row {
|
||||
padding: 24px; display: flex; flex-direction: row; justify-content: flex-end; align-items: center; gap: 16px;
|
||||
.total { font-size: 13px; color: #606266; }
|
||||
}
|
||||
|
||||
.page-ctrl {
|
||||
display: flex; flex-direction: row; gap: 8px;
|
||||
.page-num, .page-btn {
|
||||
width: 32px; height: 32px; border: 1px solid #dcdfe6; border-radius: 4px;
|
||||
display: flex; align-items: center; justify-content: center; font-size: 13px;
|
||||
&.active { background: #1890ff; color: #fff; }
|
||||
&.disabled { background: #f5f5f5; color: #ccc; }
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
Reference in New Issue
Block a user