mirror of
https://gitee.com/ulthon/ulthon_admin.git
synced 2026-11-08 03:50:50 +08:00
feat(view): 商品卡模板视觉升级,状态开关移至图面右上
This commit is contained in:
@@ -23,7 +23,9 @@
|
|||||||
{{ }} 原生插值(自动转义);处理函数内不得修改渲染上下文数据(冻结契约)
|
{{ }} 原生插值(自动转义);处理函数内不得修改渲染上下文数据(冻结契约)
|
||||||
- 事件无需自行绑定:操作按钮与 switch 经页面级委托和 form 事件天然生效
|
- 事件无需自行绑定:操作按钮与 switch 经页面级委托和 form 事件天然生效
|
||||||
取值通道(对齐官方范例契约):
|
取值通道(对齐官方范例契约):
|
||||||
- status 开关走 _cells(switch 渲染器产物)+ v-html,切换由页面级委托承接
|
- status 开关走 _cells(switch 渲染器产物)+ v-html,悬浮于图面右上角
|
||||||
|
(absolute 半透明白底小容器),不占正文行;切换由页面级委托承接
|
||||||
|
(.layui-form-switch 美化层在豁免名单内),容器只调外间距不改 DOM 结构
|
||||||
- logo 大图绕开渲染器直绑原始字段(渲染器内联缩略图样式不适合大图);
|
- logo 大图绕开渲染器直绑原始字段(渲染器内联缩略图样式不适合大图);
|
||||||
占位图标层常驻其下,img 加载失败时 @error 仅隐藏 img 露出占位(只操作
|
占位图标层常驻其下,img 加载失败时 @error 仅隐藏 img 露出占位(只操作
|
||||||
DOM,不改模板数据),无 logo 时同样显示占位
|
DOM,不改模板数据),无 logo 时同样显示占位
|
||||||
@@ -36,61 +38,73 @@
|
|||||||
:data-id="d.id"
|
:data-id="d.id"
|
||||||
:data-table-id="list.tableId"
|
:data-table-id="list.tableId"
|
||||||
:class="{'ua-data-card-checked': d._checked, 'ua-data-card-disabled': d._disabled}">
|
:class="{'ua-data-card-checked': d._checked, 'ua-data-card-disabled': d._disabled}">
|
||||||
<!-- 头部:商品大图(宽度撑满、固定高裁切不变形),无图或 404 时
|
<!-- 图区:4:3 商品大图(撑满裁切不变形、圆角随卡片),无图或 404 时
|
||||||
降级为占位图标;右上勾位图标按行选中态显示 -->
|
降级为占位图标;右上角悬浮状态开关(半透明白底小容器),
|
||||||
|
左上角勾位图标按行选中态显示 -->
|
||||||
<div class="goodscard-cover">
|
<div class="goodscard-cover">
|
||||||
<span class="goodscard-img-empty" title="未设置图片"><i class="layui-icon layui-icon-picture"></i></span>
|
<span class="goodscard-img-empty" title="未设置图片"><i class="layui-icon layui-icon-picture"></i></span>
|
||||||
<img v-if="d.logo" :src="d.logo" :alt="d.title" class="goodscard-img"
|
<img v-if="d.logo" :src="d.logo" :alt="d.title" class="goodscard-img"
|
||||||
@error="$event.target.style.display = 'none'">
|
@error="$event.target.style.display = 'none'">
|
||||||
|
<div class="goodscard-status" v-html="d._cells.status"></div>
|
||||||
<i v-if="d._checked" class="layui-icon layui-icon-ok-circle goodscard-check"></i>
|
<i v-if="d._checked" class="layui-icon layui-icon-ok-circle goodscard-check"></i>
|
||||||
</div>
|
</div>
|
||||||
<!-- 主体:名称加粗 + 分类 + 价格层级(折扣价红大字、市场价灰删除线)
|
<!-- 主体:名称(600 字重、最多两行截断)+ 分类徽标与销量同排 + 价格
|
||||||
+ 库存徽标(stock<20 红"缺货",否则绿"库存 N")+ 销量小字
|
层级(折扣价红大字、市场价灰删除线)+ 库存徽标(stock<20 红
|
||||||
+ 状态开关(_cells.status 为 switch 渲染器输出的原生 checkbox) -->
|
"缺货",否则绿"库存 N") -->
|
||||||
<div class="goodscard-body">
|
<div class="goodscard-body">
|
||||||
<div class="goodscard-title" :title="d.title">{{ d.title }}</div>
|
<div class="goodscard-title" :title="d.title">{{ d.title }}</div>
|
||||||
<div class="goodscard-cate">
|
<div class="goodscard-meta">
|
||||||
<i class="layui-icon layui-icon-tags"></i>
|
<span class="goodscard-cate">{{ d.cate && d.cate.title ? d.cate.title : '未分类' }}</span>
|
||||||
{{ d.cate && d.cate.title ? d.cate.title : '未分类' }}
|
|
||||||
</div>
|
|
||||||
<div class="goodscard-price-row">
|
|
||||||
<span class="goodscard-price">¥{{ d.discount_price }}</span>
|
|
||||||
<span v-if="parseFloat(d.market_price) > 0" class="goodscard-market-price">¥{{ d.market_price }}</span>
|
|
||||||
</div>
|
|
||||||
<div class="goodscard-flag-row">
|
|
||||||
<span v-if="d.stock < 20" class="goodscard-stock goodscard-stock-out">缺货</span>
|
|
||||||
<span v-else class="goodscard-stock goodscard-stock-in">库存 {{ d.stock }}</span>
|
|
||||||
<span class="goodscard-sales">销量 {{ d.sales }}</span>
|
<span class="goodscard-sales">销量 {{ d.sales }}</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="goodscard-status" v-html="d._cells.status"></div>
|
<div class="goodscard-price-row">
|
||||||
|
<span class="goodscard-price"><em>¥</em>{{ d.discount_price }}</span>
|
||||||
|
<span v-if="parseFloat(d.market_price) > 0" class="goodscard-market-price">¥{{ d.market_price }}</span>
|
||||||
|
</div>
|
||||||
|
<div class="goodscard-stock-row">
|
||||||
|
<span v-if="d.stock < 20" class="goodscard-stock goodscard-stock-out">缺货</span>
|
||||||
|
<span v-else class="goodscard-stock goodscard-stock-in">库存 {{ d.stock }}</span>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<!-- 底部:创建时间 + 操作按钮组(_operatHtml 为操作列渲染产物:
|
<!-- 底部:创建时间 + 操作按钮组(_operatHtml 为操作列渲染产物:
|
||||||
编辑/入库/详情/删除,已按 data-auth-* 裁剪权限),点击行为由
|
编辑/入库/详情/删除,已按 data-auth-* 裁剪权限),点击行为由
|
||||||
框架页面级委托承接 -->
|
框架页面级委托承接 -->
|
||||||
<div class="ua-data-card-footer goodscard-footer">
|
<div class="ua-data-card-footer goodscard-footer">
|
||||||
<span class="ua-data-card-time"><i class="layui-icon layui-icon-time"></i> {{ d.create_time }}</span>
|
<span class="ua-data-card-time goodscard-time">{{ d.create_time }}</span>
|
||||||
<div class="ua-data-card-operat" v-html="d._operatHtml"></div>
|
<div class="ua-data-card-operat" v-html="d._operatHtml"></div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<!-- 商品卡片形态页面级样式(示例边界:网格布局、大图封面、价格/徽标为本页
|
<!-- 商品卡片形态页面级样式(示例边界:网格布局、大图封面、悬浮开关、价格/
|
||||||
自建,卡片基础观感——边框/白底/hover/选中描边/禁用/操作按钮排布——复用
|
徽标为本页自建,卡片基础观感按统一设计语言在本页覆盖——圆角 8px、边框
|
||||||
public.css 的 .ua-data-card 族,不修改公共样式) -->
|
#eee、hover 投影、选中主题蓝描边浅蓝底;操作按钮排布仍复用 public.css
|
||||||
|
的 .ua-data-card 族,不修改公共样式) -->
|
||||||
<style>
|
<style>
|
||||||
.goodscard-list {
|
.goodscard-list {
|
||||||
display: grid;
|
display: grid;
|
||||||
grid-template-columns: repeat(auto-fill, minmax(220px, 1fr));
|
grid-template-columns: repeat(auto-fill, minmax(230px, 1fr));
|
||||||
gap: 12px;
|
gap: 12px;
|
||||||
}
|
}
|
||||||
.goodscard {
|
.goodscard {
|
||||||
padding: 0;
|
padding: 0;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
|
border: 1px solid #eee;
|
||||||
|
border-radius: 8px;
|
||||||
|
}
|
||||||
|
.goodscard:hover {
|
||||||
|
border-color: #eee;
|
||||||
|
box-shadow: 0 2px 12px rgba(0, 0, 0, .08);
|
||||||
|
}
|
||||||
|
.goodscard.ua-data-card-checked {
|
||||||
|
border-color: #1e9fff;
|
||||||
|
box-shadow: inset 0 0 0 1px #1e9fff;
|
||||||
|
background-color: rgba(30, 159, 255, 0.05);
|
||||||
}
|
}
|
||||||
.goodscard-cover {
|
.goodscard-cover {
|
||||||
position: relative;
|
position: relative;
|
||||||
height: 140px;
|
aspect-ratio: 4 / 3;
|
||||||
background-color: #f6f6f6;
|
background-color: #f6f6f6;
|
||||||
border-bottom: 1px solid #f2f2f2;
|
border-bottom: 1px solid #f2f2f2;
|
||||||
}
|
}
|
||||||
@@ -103,8 +117,8 @@
|
|||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
color: #c2c2c2;
|
color: #d5d5d5;
|
||||||
font-size: 32px;
|
font-size: 36px;
|
||||||
}
|
}
|
||||||
.goodscard-img {
|
.goodscard-img {
|
||||||
position: relative;
|
position: relative;
|
||||||
@@ -113,85 +127,112 @@
|
|||||||
height: 100%;
|
height: 100%;
|
||||||
object-fit: cover;
|
object-fit: cover;
|
||||||
}
|
}
|
||||||
|
.goodscard-status {
|
||||||
|
position: absolute;
|
||||||
|
top: 8px;
|
||||||
|
right: 8px;
|
||||||
|
z-index: 2;
|
||||||
|
padding: 2px 6px;
|
||||||
|
background-color: rgba(255, 255, 255, 0.85);
|
||||||
|
border-radius: 8px;
|
||||||
|
box-shadow: 0 1px 4px rgba(0, 0, 0, 0.12);
|
||||||
|
}
|
||||||
|
.goodscard-status .layui-form-switch {
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
.goodscard-check {
|
.goodscard-check {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
top: 6px;
|
top: 8px;
|
||||||
right: 6px;
|
left: 8px;
|
||||||
color: rgb(22, 183, 119);
|
color: #1e9fff;
|
||||||
font-size: 22px;
|
font-size: 22px;
|
||||||
background-color: #fff;
|
background-color: #fff;
|
||||||
border-radius: 50%;
|
border-radius: 50%;
|
||||||
}
|
}
|
||||||
.goodscard-body {
|
.goodscard-body {
|
||||||
flex: 1;
|
flex: 1;
|
||||||
padding: 8px 12px 0;
|
padding: 10px 12px 12px;
|
||||||
}
|
}
|
||||||
.goodscard-title {
|
.goodscard-title {
|
||||||
|
display: -webkit-box;
|
||||||
|
overflow: hidden;
|
||||||
|
min-height: 40px;
|
||||||
|
-webkit-box-orient: vertical;
|
||||||
|
-webkit-line-clamp: 2;
|
||||||
|
font-weight: 600;
|
||||||
|
font-size: 14px;
|
||||||
|
line-height: 20px;
|
||||||
|
}
|
||||||
|
.goodscard-meta {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: space-between;
|
||||||
|
margin-top: 6px;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
text-overflow: ellipsis;
|
|
||||||
white-space: nowrap;
|
|
||||||
font-weight: bold;
|
|
||||||
line-height: 22px;
|
|
||||||
}
|
}
|
||||||
.goodscard-cate {
|
.goodscard-cate {
|
||||||
margin-top: 2px;
|
flex: none;
|
||||||
|
max-width: 70%;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
text-overflow: ellipsis;
|
text-overflow: ellipsis;
|
||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
color: #999;
|
padding: 2px 8px;
|
||||||
|
background-color: #f5f5f5;
|
||||||
|
border-radius: 10px;
|
||||||
|
color: #666;
|
||||||
font-size: 12px;
|
font-size: 12px;
|
||||||
line-height: 18px;
|
line-height: 16px;
|
||||||
}
|
}
|
||||||
.goodscard-cate .layui-icon {
|
.goodscard-sales {
|
||||||
|
flex: none;
|
||||||
|
color: #999;
|
||||||
font-size: 12px;
|
font-size: 12px;
|
||||||
}
|
}
|
||||||
.goodscard-price-row {
|
.goodscard-price-row {
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: baseline;
|
align-items: baseline;
|
||||||
margin-top: 6px;
|
margin-top: 8px;
|
||||||
}
|
}
|
||||||
.goodscard-price {
|
.goodscard-price {
|
||||||
color: #ff5722;
|
color: #ff5722;
|
||||||
font-size: 18px;
|
font-size: 18px;
|
||||||
font-weight: bold;
|
font-weight: 600;
|
||||||
|
}
|
||||||
|
.goodscard-price em {
|
||||||
|
font-style: normal;
|
||||||
|
font-size: 14px;
|
||||||
}
|
}
|
||||||
.goodscard-market-price {
|
.goodscard-market-price {
|
||||||
margin-left: 8px;
|
margin-left: 8px;
|
||||||
color: #c2c2c2;
|
color: #999;
|
||||||
font-size: 12px;
|
font-size: 12px;
|
||||||
text-decoration: line-through;
|
text-decoration: line-through;
|
||||||
}
|
}
|
||||||
.goodscard-flag-row {
|
.goodscard-stock-row {
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
justify-content: space-between;
|
margin-top: 8px;
|
||||||
margin-top: 6px;
|
|
||||||
}
|
}
|
||||||
.goodscard-stock {
|
.goodscard-stock {
|
||||||
padding: 0 6px;
|
padding: 2px 8px;
|
||||||
border-radius: 2px;
|
border-radius: 10px;
|
||||||
font-size: 12px;
|
font-size: 12px;
|
||||||
line-height: 18px;
|
line-height: 16px;
|
||||||
}
|
}
|
||||||
.goodscard-stock-out {
|
.goodscard-stock-out {
|
||||||
color: #ff5722;
|
color: #ff5722;
|
||||||
background-color: rgba(255, 87, 34, 0.1);
|
background-color: rgba(255, 87, 34, 0.08);
|
||||||
}
|
}
|
||||||
.goodscard-stock-in {
|
.goodscard-stock-in {
|
||||||
color: rgb(22, 183, 119);
|
color: rgb(22, 183, 119);
|
||||||
background-color: rgba(22, 183, 119, 0.1);
|
background-color: rgba(22, 183, 119, 0.08);
|
||||||
}
|
|
||||||
.goodscard-sales {
|
|
||||||
color: #999;
|
|
||||||
font-size: 12px;
|
|
||||||
}
|
|
||||||
.goodscard-status {
|
|
||||||
margin-top: 6px;
|
|
||||||
text-align: right;
|
|
||||||
}
|
}
|
||||||
.goodscard-footer {
|
.goodscard-footer {
|
||||||
margin-top: 8px;
|
margin-top: 0;
|
||||||
padding: 8px 12px 10px;
|
padding: 8px 12px;
|
||||||
|
}
|
||||||
|
.goodscard-time .layui-icon {
|
||||||
|
font-size: 12px;
|
||||||
}
|
}
|
||||||
@media (max-width: 768px) {
|
@media (max-width: 768px) {
|
||||||
.goodscard-list {
|
.goodscard-list {
|
||||||
|
|||||||
Reference in New Issue
Block a user