feat(aps): 新增APS排产管理模块完整功能
本次提交完成APS(高级计划与排程)模块的全量开发: 1. 新增CRM订单相关API接口,包含列表、详情、明细查询 2. 新增产需单相关CRUD API与页面,支持排产单管理与订单绑定 3. 新增按日期查询排产单、订单下钻详情页面 4. 为排产单实体类添加日期格式化注解,修复参数绑定问题 5. 统一封装APS模块主题样式,提供通用混入与变量 6. 实现产需单与销售订单的绑定解绑、明细自动生成功能
This commit is contained in:
@@ -8,6 +8,7 @@ import javax.validation.constraints.*;
|
|||||||
import java.math.BigDecimal;
|
import java.math.BigDecimal;
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
import com.fasterxml.jackson.annotation.JsonFormat;
|
import com.fasterxml.jackson.annotation.JsonFormat;
|
||||||
|
import org.springframework.format.annotation.DateTimeFormat;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 排产单主业务对象 sch_prod_schedule
|
* 排产单主业务对象 sch_prod_schedule
|
||||||
@@ -33,6 +34,8 @@ public class SchProdScheduleBo extends BaseEntity {
|
|||||||
/**
|
/**
|
||||||
* 生产日期(和合同号组成业务关联键)
|
* 生产日期(和合同号组成业务关联键)
|
||||||
*/
|
*/
|
||||||
|
@DateTimeFormat(pattern = "yyyy-MM-dd")
|
||||||
|
@JsonFormat(pattern = "yyyy-MM-dd")
|
||||||
private Date prodDate;
|
private Date prodDate;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
27
klp-ui/src/api/aps/order.js
Normal file
27
klp-ui/src/api/aps/order.js
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
import request from '@/utils/request'
|
||||||
|
|
||||||
|
// 查询 CRM 订单列表(只读)
|
||||||
|
export function listCrmOrder(query) {
|
||||||
|
return request({
|
||||||
|
url: '/crm/order/list',
|
||||||
|
method: 'get',
|
||||||
|
params: query
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 查询 CRM 订单详情
|
||||||
|
export function getCrmOrder(orderId) {
|
||||||
|
return request({
|
||||||
|
url: '/crm/order/' + orderId,
|
||||||
|
method: 'get'
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 查询 CRM 订单明细列表
|
||||||
|
export function listCrmOrderItem(query) {
|
||||||
|
return request({
|
||||||
|
url: '/crm/orderItem/list',
|
||||||
|
method: 'get',
|
||||||
|
params: query
|
||||||
|
})
|
||||||
|
}
|
||||||
120
klp-ui/src/api/aps/requirement.js
Normal file
120
klp-ui/src/api/aps/requirement.js
Normal file
@@ -0,0 +1,120 @@
|
|||||||
|
import request from '@/utils/request'
|
||||||
|
|
||||||
|
// ====== 产需单(SchProdSchedule)CRUD ======
|
||||||
|
|
||||||
|
// 查询产需单列表
|
||||||
|
export function listRequirement(query) {
|
||||||
|
return request({
|
||||||
|
url: '/flow/prodSchedule/list',
|
||||||
|
method: 'get',
|
||||||
|
params: query
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 查询产需单详情
|
||||||
|
export function getRequirement(scheduleId) {
|
||||||
|
return request({
|
||||||
|
url: '/flow/prodSchedule/' + scheduleId,
|
||||||
|
method: 'get'
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 新增产需单
|
||||||
|
export function addRequirement(data) {
|
||||||
|
return request({
|
||||||
|
url: '/flow/prodSchedule',
|
||||||
|
method: 'post',
|
||||||
|
data
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 修改产需单
|
||||||
|
export function updateRequirement(data) {
|
||||||
|
return request({
|
||||||
|
url: '/flow/prodSchedule',
|
||||||
|
method: 'put',
|
||||||
|
data
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 删除产需单
|
||||||
|
export function delRequirement(scheduleIds) {
|
||||||
|
return request({
|
||||||
|
url: '/flow/prodSchedule/' + scheduleIds,
|
||||||
|
method: 'delete'
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// ====== 产需单明细(SchProdScheduleDetail) ======
|
||||||
|
|
||||||
|
// 查询产需单明细列表
|
||||||
|
export function listRequirementDetail(query) {
|
||||||
|
return request({
|
||||||
|
url: '/flow/prodScheduleDetail/list',
|
||||||
|
method: 'get',
|
||||||
|
params: query
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 新增产需单明细
|
||||||
|
export function addRequirementDetail(data) {
|
||||||
|
return request({
|
||||||
|
url: '/flow/prodScheduleDetail',
|
||||||
|
method: 'post',
|
||||||
|
data
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 修改产需单明细
|
||||||
|
export function updateRequirementDetail(data) {
|
||||||
|
return request({
|
||||||
|
url: '/flow/prodScheduleDetail',
|
||||||
|
method: 'put',
|
||||||
|
data
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 删除产需单明细
|
||||||
|
export function delRequirementDetail(detailIds) {
|
||||||
|
return request({
|
||||||
|
url: '/flow/prodScheduleDetail/' + detailIds,
|
||||||
|
method: 'delete'
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// ====== 销售订单-产需单关联(SchSaleScheduleRel) ======
|
||||||
|
|
||||||
|
// 查询关联列表
|
||||||
|
export function listRel(query) {
|
||||||
|
return request({
|
||||||
|
url: '/flow/saleScheduleRel/list',
|
||||||
|
method: 'get',
|
||||||
|
params: query
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 新增关联(绑定订单)
|
||||||
|
export function addRel(data) {
|
||||||
|
return request({
|
||||||
|
url: '/flow/saleScheduleRel',
|
||||||
|
method: 'post',
|
||||||
|
data
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 修改关联
|
||||||
|
export function updateRel(data) {
|
||||||
|
return request({
|
||||||
|
url: '/flow/saleScheduleRel',
|
||||||
|
method: 'put',
|
||||||
|
data
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 删除关联(解绑订单)
|
||||||
|
export function delRel(relIds) {
|
||||||
|
return request({
|
||||||
|
url: '/flow/saleScheduleRel/' + relIds,
|
||||||
|
method: 'delete'
|
||||||
|
})
|
||||||
|
}
|
||||||
35
klp-ui/src/api/aps/schedule.js
Normal file
35
klp-ui/src/api/aps/schedule.js
Normal file
@@ -0,0 +1,35 @@
|
|||||||
|
import request from '@/utils/request'
|
||||||
|
|
||||||
|
// 按日期查询产需单列表
|
||||||
|
export function listScheduleByDate(prodDate) {
|
||||||
|
return request({
|
||||||
|
url: '/flow/prodSchedule/list',
|
||||||
|
method: 'get',
|
||||||
|
params: { prodDate }
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 查询产需单明细(用于排产单聚合)
|
||||||
|
export function listScheduleDetail(scheduleId) {
|
||||||
|
return request({
|
||||||
|
url: '/flow/prodScheduleDetail/list',
|
||||||
|
method: 'get',
|
||||||
|
params: { scheduleId }
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 查询 CRM 订单信息(用于下钻)
|
||||||
|
export function getCrmOrderInfo(orderId) {
|
||||||
|
return request({
|
||||||
|
url: '/crm/order/' + orderId,
|
||||||
|
method: 'get'
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 查询 CRM 订单明细(用于下钻展示)
|
||||||
|
export function getCrmOrderItem(orderDetailId) {
|
||||||
|
return request({
|
||||||
|
url: '/crm/orderItem/' + orderDetailId,
|
||||||
|
method: 'get'
|
||||||
|
})
|
||||||
|
}
|
||||||
445
klp-ui/src/views/wms/post/aps/order.vue
Normal file
445
klp-ui/src/views/wms/post/aps/order.vue
Normal file
@@ -0,0 +1,445 @@
|
|||||||
|
<template>
|
||||||
|
<div class="app-container" style="height: calc(100vh - 84px); display: flex;">
|
||||||
|
<!-- 左侧订单列表 -->
|
||||||
|
<div class="left-panel" v-loading="orderLoading" style="width: 30%; border-right: 1px solid #e4e7ed; overflow-y: auto;">
|
||||||
|
<!-- 筛选区 -->
|
||||||
|
<div class="filter-section" style="padding: 10px; border-bottom: 1px solid #e4e7ed;">
|
||||||
|
<!-- 第一行:搜索 + 按钮 + 记录数 -->
|
||||||
|
<div style="display: flex; align-items: center; justify-content: space-between; margin-bottom: 10px;">
|
||||||
|
<div style="display: flex; align-items: center; gap: 4px; flex-wrap: wrap;">
|
||||||
|
<el-input v-model="queryParams.keyword" placeholder="请输入关键字" clearable
|
||||||
|
@keyup.enter.native="handleSearch" style="width: 160px;" />
|
||||||
|
<el-button class="aps-btn-red" icon="el-icon-search" size="mini" @click="handleSearch">筛选</el-button>
|
||||||
|
<el-button icon="el-icon-sort" size="mini" @click="toggleMoreFilter"
|
||||||
|
:class="showMoreFilter ? 'aps-btn-red' : 'aps-btn-silver'"></el-button>
|
||||||
|
</div>
|
||||||
|
<div style="font-size: 12px; color: #909399;">
|
||||||
|
共 <span class="aps-total-count">{{ total }}</span> 条记录
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 第二行:日期范围 -->
|
||||||
|
<div style="display: flex; align-items: center; gap: 16px; flex-wrap: wrap; margin-bottom: 4px;">
|
||||||
|
<div style="display: flex; align-items: center; gap: 4px; font-size: 13px; color: #606266;">
|
||||||
|
<span style="white-space: nowrap;">签订日期:</span>
|
||||||
|
<el-date-picker clearable v-model="queryParams.signDateStart" type="date" value-format="yyyy-MM-dd"
|
||||||
|
placeholder="签订开始" style="width: 150px;" @change="handleSearch" />
|
||||||
|
<span>~</span>
|
||||||
|
<el-date-picker clearable v-model="queryParams.signDateEnd" type="date" value-format="yyyy-MM-dd"
|
||||||
|
placeholder="签订结束" style="width: 150px;" @change="handleSearch" />
|
||||||
|
</div>
|
||||||
|
<div style="display: flex; align-items: center; gap: 4px; font-size: 13px; color: #606266;">
|
||||||
|
<span style="white-space: nowrap;">交货日期:</span>
|
||||||
|
<el-date-picker clearable v-model="queryParams.deliveryDateStart" type="date" value-format="yyyy-MM-dd"
|
||||||
|
placeholder="交货开始" style="width: 150px;" @change="handleSearch" />
|
||||||
|
<span>~</span>
|
||||||
|
<el-date-picker clearable v-model="queryParams.deliveryDateEnd" type="date" value-format="yyyy-MM-dd"
|
||||||
|
placeholder="交货结束" style="width: 150px;" @change="handleSearch" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 第三行:更多筛选条件 -->
|
||||||
|
<div v-show="showMoreFilter" class="more-filter"
|
||||||
|
style="margin-top: 8px; padding-top: 10px; border-top: 1px dashed #e4e7ed;">
|
||||||
|
<el-form :model="queryParams" ref="queryForm" size="small" :inline="true" label-width="80px">
|
||||||
|
<el-form-item label="订单编号" prop="orderCode">
|
||||||
|
<el-input v-model="queryParams.orderCode" placeholder="请输入订单编号" clearable
|
||||||
|
@keyup.enter.native="handleSearch" />
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="销售员" prop="salesman">
|
||||||
|
<el-select v-model="queryParams.salesman" placeholder="请选择销售员" clearable style="width: 140px;">
|
||||||
|
<el-option v-for="item in dict.type.wip_pack_saleman" :key="item.value" :label="item.label"
|
||||||
|
:value="item.value" />
|
||||||
|
</el-select>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="订单状态" prop="orderStatus">
|
||||||
|
<el-select v-model="queryParams.orderStatus" placeholder="请选择订单状态" clearable style="width: 140px;">
|
||||||
|
<el-option v-for="(value, key) in ORDER_STATUS" :key="value" :label="key" :value="value" />
|
||||||
|
</el-select>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item>
|
||||||
|
<el-button class="aps-btn-silver" icon="el-icon-refresh" size="mini" @click="resetQuery">重置</el-button>
|
||||||
|
</el-form-item>
|
||||||
|
</el-form>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 列表区域 -->
|
||||||
|
<div class="custom-list">
|
||||||
|
<div class="list-body">
|
||||||
|
<div
|
||||||
|
v-for="item in orderList"
|
||||||
|
:key="item.orderId"
|
||||||
|
class="list-item"
|
||||||
|
:class="{ 'list-item-active': currentOrder && currentOrder.orderId === item.orderId }"
|
||||||
|
@click="handleOrderClick(item)"
|
||||||
|
>
|
||||||
|
<!-- 第一行:订单编号 + 客户公司 -->
|
||||||
|
<div style="display: flex; justify-content: space-between; align-items: center; margin-bottom: 8px;">
|
||||||
|
<div style="display: flex; align-items: center; gap: 8px;">
|
||||||
|
<div style="font-weight: bold;">{{ item.contractName }}</div>
|
||||||
|
</div>
|
||||||
|
<div style="font-size: 12px; color: #606266;">{{ item.companyName }}</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 第二行:销售员 + 合同号 -->
|
||||||
|
<div style="font-size: 12px; color: #909399; margin-bottom: 6px;">
|
||||||
|
<span>销售员: {{ item.salesman }}</span>
|
||||||
|
<span style="margin-left: 20px;">合同号: {{ item.contractCode }}</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 第三行:签订时间 + 交货日期 -->
|
||||||
|
<div style="font-size: 12px; color: #909399; margin-bottom: 6px;">
|
||||||
|
<span>签订时间: {{ item.signTime }}</span>
|
||||||
|
<span style="margin-left: 20px;">交货日期: {{ item.deliveryDate }}</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 第四行:签订地点 + 状态 -->
|
||||||
|
<div style="display: flex; justify-content: space-between; align-items: center;">
|
||||||
|
<div style="font-size: 12px; color: #909399;">
|
||||||
|
签订地点: {{ item.signLocation || '-' }}
|
||||||
|
</div>
|
||||||
|
<el-tag
|
||||||
|
:type="statusTagType(item.orderStatus)"
|
||||||
|
size="small"
|
||||||
|
>{{ statusLabel(item.orderStatus) }}</el-tag>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div v-if="orderList.length === 0 && !orderLoading" style="padding: 40px; text-align: center; color: #909399;">
|
||||||
|
暂无订单数据
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<pagination
|
||||||
|
v-show="total > 0"
|
||||||
|
:total="total"
|
||||||
|
:page.sync="queryParams.pageNum"
|
||||||
|
:limit.sync="queryParams.pageSize"
|
||||||
|
@pagination="getList"
|
||||||
|
style="padding: 10px; margin-bottom: 10px !important;"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 右侧内容区域 -->
|
||||||
|
<div class="right-panel" v-if="currentOrder && currentOrder.orderId" style="flex: 1; display: flex; flex-direction: column;">
|
||||||
|
<div class="detail-panel">
|
||||||
|
<!-- 订单基本信息(含甲乙双方)卡片 -->
|
||||||
|
<div class="detail-card">
|
||||||
|
<div class="detail-card-header">
|
||||||
|
<span>订单基本信息</span>
|
||||||
|
</div>
|
||||||
|
<div class="detail-card-body">
|
||||||
|
<div class="form-grid-2">
|
||||||
|
<div class="form-field"><label>销售员</label><div class="field-value">{{ currentOrder.salesman }}</div></div>
|
||||||
|
<div class="form-field"><label>合同号</label><div class="field-value">{{ currentOrder.contractCode }}</div></div>
|
||||||
|
<div class="form-field"><label>签订时间</label><div class="field-value">{{ currentOrder.signTime }}</div></div>
|
||||||
|
<div class="form-field"><label>交货日期</label><div class="field-value">{{ currentOrder.deliveryDate }}</div></div>
|
||||||
|
<div class="form-field"><label>订单总金额</label><div class="field-value">{{ currentOrder.orderAmount }}</div></div>
|
||||||
|
<div class="form-field"><label>签订地点</label><div class="field-value">{{ currentOrder.signLocation }}</div></div>
|
||||||
|
<div class="form-field" style="grid-column:1/3;"><label>备注</label><div class="field-value">{{ currentOrder.remark }}</div></div>
|
||||||
|
</div>
|
||||||
|
<div class="section-divider"></div>
|
||||||
|
<div class="form-grid-2">
|
||||||
|
<div class="form-field"><label>供方名称(甲方)</label><div class="field-value">{{ currentOrder.supplier }}</div></div>
|
||||||
|
<div class="form-field"><label>供方地址</label><div class="field-value">{{ currentOrder.supplierAddress }}</div></div>
|
||||||
|
<div class="form-field"><label>供方电话</label><div class="field-value">{{ currentOrder.supplierPhone }}</div></div>
|
||||||
|
<div class="form-field"><label>供方开户行</label><div class="field-value">{{ currentOrder.supplierBank }}</div></div>
|
||||||
|
<div class="form-field"><label>供方账号</label><div class="field-value">{{ currentOrder.supplierAccount }}</div></div>
|
||||||
|
<div class="form-field"><label>供方税号</label><div class="field-value">{{ currentOrder.supplierTaxNo }}</div></div>
|
||||||
|
<div class="form-field" style="border-top:1px solid #e8e8e8;padding-top:8px;margin-top:4px;grid-column:1/3;"></div>
|
||||||
|
<div class="form-field"><label>需方名称(乙方)</label><div class="field-value">{{ currentOrder.customer }}</div></div>
|
||||||
|
<div class="form-field"><label>需方地址</label><div class="field-value">{{ currentOrder.customerAddress }}</div></div>
|
||||||
|
<div class="form-field"><label>需方电话</label><div class="field-value">{{ currentOrder.customerPhone }}</div></div>
|
||||||
|
<div class="form-field"><label>需方开户行</label><div class="field-value">{{ currentOrder.customerBank }}</div></div>
|
||||||
|
<div class="form-field"><label>需方账号</label><div class="field-value">{{ currentOrder.customerAccount }}</div></div>
|
||||||
|
<div class="form-field"><label>需方税号</label><div class="field-value">{{ currentOrder.customerTaxNo }}</div></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 订单明细卡片 -->
|
||||||
|
<div class="detail-card">
|
||||||
|
<div class="detail-card-header">
|
||||||
|
<span>订单明细({{ productList.length }} 条)</span>
|
||||||
|
</div>
|
||||||
|
<div class="detail-card-body" style="padding:0;">
|
||||||
|
<div v-if="productList.length > 0" class="aps-product-table-wrap">
|
||||||
|
<el-table :data="productList" border size="small" class="aps-product-table">
|
||||||
|
<el-table-column label="规格" prop="spec" min-width="120" />
|
||||||
|
<el-table-column label="材质" prop="material" width="100" align="center" />
|
||||||
|
<el-table-column label="数量(吨)" prop="quantity" width="90" align="right" />
|
||||||
|
<el-table-column label="含税单价" prop="taxPrice" width="100" align="right" />
|
||||||
|
<el-table-column label="含税总额" prop="taxTotal" width="100" align="right" />
|
||||||
|
<el-table-column label="无税单价" prop="noTaxPrice" width="100" align="right" />
|
||||||
|
<el-table-column label="无税总额" prop="noTaxTotal" width="100" align="right" />
|
||||||
|
<el-table-column label="税额" prop="taxAmount" width="90" align="right" />
|
||||||
|
<el-table-column label="备注" prop="remark" min-width="120" />
|
||||||
|
</el-table>
|
||||||
|
<div class="aps-product-summary">
|
||||||
|
<span>产品名称:{{ productName }}</span>
|
||||||
|
<span>总数量:{{ totalQuantity }} 吨</span>
|
||||||
|
<span>含税总额:{{ totalTaxTotal }}</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<el-empty v-else description="暂无产品明细" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div v-else style="flex: 1; display: flex; flex-direction: column;">
|
||||||
|
<el-empty description="选择订单后查看内容" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import { listCrmOrder } from '@/api/aps/order'
|
||||||
|
import { parseProductContent } from '@/utils/productContent'
|
||||||
|
import { ORDER_STATUS } from '@/views/crm/js/enum'
|
||||||
|
import FileList from '@/components/FileList'
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: 'ApsOrder',
|
||||||
|
components: { FileList },
|
||||||
|
dicts: ['wip_pack_saleman'],
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
ORDER_STATUS,
|
||||||
|
showMoreFilter: false,
|
||||||
|
orderLoading: false,
|
||||||
|
orderList: [],
|
||||||
|
total: 0,
|
||||||
|
currentOrder: null,
|
||||||
|
productList: [],
|
||||||
|
productName: '',
|
||||||
|
totalQuantity: 0,
|
||||||
|
totalTaxTotal: 0,
|
||||||
|
queryParams: {
|
||||||
|
keyword: '',
|
||||||
|
orderCode: '',
|
||||||
|
salesman: '',
|
||||||
|
orderStatus: undefined,
|
||||||
|
signDateStart: undefined,
|
||||||
|
signDateEnd: undefined,
|
||||||
|
deliveryDateStart: undefined,
|
||||||
|
deliveryDateEnd: undefined,
|
||||||
|
pageNum: 1,
|
||||||
|
pageSize: 10
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
created() {
|
||||||
|
this.getList()
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
toggleMoreFilter() {
|
||||||
|
this.showMoreFilter = !this.showMoreFilter
|
||||||
|
},
|
||||||
|
handleSearch() {
|
||||||
|
this.queryParams.pageNum = 1
|
||||||
|
this.getList()
|
||||||
|
},
|
||||||
|
resetQuery() {
|
||||||
|
this.queryParams.orderCode = ''
|
||||||
|
this.queryParams.salesman = ''
|
||||||
|
this.queryParams.orderStatus = undefined
|
||||||
|
this.queryParams.signDateStart = undefined
|
||||||
|
this.queryParams.signDateEnd = undefined
|
||||||
|
this.queryParams.deliveryDateStart = undefined
|
||||||
|
this.queryParams.deliveryDateEnd = undefined
|
||||||
|
this.handleSearch()
|
||||||
|
},
|
||||||
|
getList() {
|
||||||
|
this.orderLoading = true
|
||||||
|
listCrmOrder(this.queryParams).then(res => {
|
||||||
|
this.orderList = res.rows || []
|
||||||
|
this.total = res.total || 0
|
||||||
|
}).catch(() => {
|
||||||
|
this.orderList = []
|
||||||
|
this.total = 0
|
||||||
|
}).finally(() => {
|
||||||
|
this.orderLoading = false
|
||||||
|
})
|
||||||
|
},
|
||||||
|
handleOrderClick(order) {
|
||||||
|
this.currentOrder = order
|
||||||
|
this.parseProductContent(order)
|
||||||
|
},
|
||||||
|
parseProductContent(order) {
|
||||||
|
if (!order || !order.productContent) {
|
||||||
|
this.productList = []
|
||||||
|
this.productName = ''
|
||||||
|
this.totalQuantity = 0
|
||||||
|
this.totalTaxTotal = 0
|
||||||
|
return
|
||||||
|
}
|
||||||
|
const parsed = parseProductContent(order.productContent)
|
||||||
|
this.productList = parsed.products || []
|
||||||
|
this.productName = parsed.productName || ''
|
||||||
|
this.totalQuantity = parsed.totalQuantity || 0
|
||||||
|
this.totalTaxTotal = parsed.totalTaxTotal || 0
|
||||||
|
},
|
||||||
|
statusTagType(status) {
|
||||||
|
const map = { 0: 'info', 1: 'warning', 2: 'primary', 3: 'success', 4: 'success' }
|
||||||
|
return map[status] || 'info'
|
||||||
|
},
|
||||||
|
statusLabel(status) {
|
||||||
|
const labels = { 0: '待生产', 1: '生产中', 2: '部分发货', 3: '已发货', 4: '已签收' }
|
||||||
|
return labels[status] || '未知'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped lang="scss">
|
||||||
|
@import './scss/aps-theme.scss';
|
||||||
|
|
||||||
|
.app-container {
|
||||||
|
overflow: hidden;
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.left-panel {
|
||||||
|
height: calc(100vh - 84px);
|
||||||
|
box-sizing: border-box;
|
||||||
|
overflow-y: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.right-panel {
|
||||||
|
height: calc(100vh - 84px);
|
||||||
|
overflow: hidden;
|
||||||
|
min-height: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ====== 左侧列表(参照 ContractList.vue) ======
|
||||||
|
.custom-list {
|
||||||
|
border: 1px solid #e4e7ed;
|
||||||
|
border-radius: 4px;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
.list-item {
|
||||||
|
padding: 10px;
|
||||||
|
border-bottom: 2px solid #dddddd;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
.list-item:hover {
|
||||||
|
background-color: $aps-silver-1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.list-item-active {
|
||||||
|
background-color: $aps-red-1;
|
||||||
|
border-left: 3px solid $aps-red-2;
|
||||||
|
}
|
||||||
|
|
||||||
|
.aps-total-count {
|
||||||
|
color: $aps-red-2;
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
|
||||||
|
.aps-btn-red {
|
||||||
|
@include aps-btn-red;
|
||||||
|
}
|
||||||
|
|
||||||
|
.aps-btn-silver {
|
||||||
|
@include aps-btn-silver;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ====== 右侧详情面板(参照 HTML 设计稿) ======
|
||||||
|
.detail-panel {
|
||||||
|
flex: 1;
|
||||||
|
overflow-y: scroll;
|
||||||
|
padding: 16px;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 16px;
|
||||||
|
background: $aps-bg;
|
||||||
|
min-height: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.detail-card {
|
||||||
|
background: $aps-white;
|
||||||
|
border: 1px solid $aps-border;
|
||||||
|
border-radius: $aps-radius;
|
||||||
|
box-shadow: $aps-shadow-sm;
|
||||||
|
}
|
||||||
|
|
||||||
|
.detail-card-header {
|
||||||
|
background: linear-gradient(to right, $aps-red-2, $aps-red-3);
|
||||||
|
color: white;
|
||||||
|
padding: 8px 14px;
|
||||||
|
font-size: 13px;
|
||||||
|
font-weight: 600;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: space-between;
|
||||||
|
}
|
||||||
|
|
||||||
|
.detail-card-body {
|
||||||
|
padding: 14px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.form-grid-2 {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: repeat(2, 1fr);
|
||||||
|
gap: 10px 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.form-field {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 3px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.form-field label {
|
||||||
|
font-size: 11px;
|
||||||
|
color: $aps-text-muted;
|
||||||
|
font-weight: 500;
|
||||||
|
}
|
||||||
|
|
||||||
|
.form-field .field-value {
|
||||||
|
font-size: 13px;
|
||||||
|
color: $aps-text;
|
||||||
|
padding: 4px 0;
|
||||||
|
border-bottom: 1px solid $aps-silver-mid;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ====== 产品明细 ======
|
||||||
|
.aps-detail-title {
|
||||||
|
font-size: 15px;
|
||||||
|
font-weight: 600;
|
||||||
|
color: $aps-silver-5;
|
||||||
|
border-left: 3px solid $aps-red-2;
|
||||||
|
padding-left: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.aps-product-table-wrap {
|
||||||
|
border: 1px solid $aps-silver-3;
|
||||||
|
border-radius: 4px;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
.aps-product-table {
|
||||||
|
width: 100%;
|
||||||
|
|
||||||
|
::v-deep th {
|
||||||
|
background: $aps-silver-1 !important;
|
||||||
|
color: $aps-silver-5 !important;
|
||||||
|
font-weight: 600 !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.aps-product-summary {
|
||||||
|
display: flex;
|
||||||
|
gap: 24px;
|
||||||
|
padding: 8px 16px;
|
||||||
|
background: $aps-silver-1;
|
||||||
|
border-top: 1px solid $aps-silver-3;
|
||||||
|
font-size: 13px;
|
||||||
|
color: $aps-silver-5;
|
||||||
|
font-weight: 500;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
1022
klp-ui/src/views/wms/post/aps/requirement.vue
Normal file
1022
klp-ui/src/views/wms/post/aps/requirement.vue
Normal file
File diff suppressed because it is too large
Load Diff
316
klp-ui/src/views/wms/post/aps/schedule.vue
Normal file
316
klp-ui/src/views/wms/post/aps/schedule.vue
Normal file
@@ -0,0 +1,316 @@
|
|||||||
|
<template>
|
||||||
|
<div class="aps-sch-page">
|
||||||
|
<!-- 顶部工具栏 -->
|
||||||
|
<div class="aps-sch-toolbar">
|
||||||
|
<span class="aps-sch-label">生产日期:</span>
|
||||||
|
<el-date-picker
|
||||||
|
v-model="queryDate"
|
||||||
|
type="date"
|
||||||
|
placeholder="选择生产日期"
|
||||||
|
value-format="yyyy-MM-dd"
|
||||||
|
size="small"
|
||||||
|
style="width:160px"
|
||||||
|
@change="handleDateChange"
|
||||||
|
/>
|
||||||
|
<el-button size="small" class="aps-btn-red" icon="el-icon-search" @click="handleQuery">查询</el-button>
|
||||||
|
<div class="aps-sch-summary" v-if="summaryText">
|
||||||
|
<span>{{ summaryText }}</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 排产明细卡片 -->
|
||||||
|
<div class="detail-card aps-sch-card">
|
||||||
|
<div class="detail-card-header">
|
||||||
|
<span>排产明细</span>
|
||||||
|
<span v-if="detailList.length > 0" style="font-weight:normal;font-size:12px;opacity:0.8;">
|
||||||
|
共 {{ scheduleList.length }} 个产需单,{{ detailList.length }} 条明细
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
<div class="detail-card-body" style="padding:0;" v-loading="schLoading">
|
||||||
|
<el-table
|
||||||
|
v-if="detailList.length > 0"
|
||||||
|
:data="detailList"
|
||||||
|
border
|
||||||
|
size="small"
|
||||||
|
class="aps-table"
|
||||||
|
@row-click="handleRowClick"
|
||||||
|
>
|
||||||
|
<el-table-column label="排产单号" prop="scheduleNo" min-width="140" fixed="left">
|
||||||
|
<template slot-scope="{ row }">
|
||||||
|
<span class="sch-link-text">{{ row.scheduleNo }}</span>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
<el-table-column label="规格" prop="spec" min-width="120" />
|
||||||
|
<el-table-column label="材质" prop="material" width="90" align="center" />
|
||||||
|
<el-table-column label="排产吨数" prop="scheduleWeight" width="100" align="right" />
|
||||||
|
<el-table-column label="品名" prop="productType" min-width="100" />
|
||||||
|
<el-table-column label="订货单位" prop="customerName" min-width="140" />
|
||||||
|
<el-table-column label="业务员" prop="businessUser" width="80" align="center" />
|
||||||
|
<el-table-column label="交货期(天)" prop="deliveryCycle" width="90" align="center" />
|
||||||
|
<el-table-column label="备注" prop="remark" min-width="140" />
|
||||||
|
</el-table>
|
||||||
|
<div v-else-if="!schLoading" style="padding:40px;text-align:center;color:#909399;">
|
||||||
|
{{ hasQueried ? '该日期暂无排产数据' : '请选择日期查询排产数据' }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 下钻弹窗 -->
|
||||||
|
<el-dialog
|
||||||
|
title="来源订单信息"
|
||||||
|
:visible.sync="drillDialogVisible"
|
||||||
|
width="600px"
|
||||||
|
append-to-body
|
||||||
|
>
|
||||||
|
<div v-if="drillOrder" class="detail-card" style="border:none;box-shadow:none;">
|
||||||
|
<div class="detail-card-body">
|
||||||
|
<div class="form-grid-2">
|
||||||
|
<div class="form-field"><label>订单编号</label><div class="field-value">{{ drillOrder.orderCode }}</div></div>
|
||||||
|
<div class="form-field"><label>销售员</label><div class="field-value">{{ drillOrder.salesman }}</div></div>
|
||||||
|
<div class="form-field"><label>客户公司</label><div class="field-value">{{ drillOrder.companyName }}</div></div>
|
||||||
|
<div class="form-field"><label>联系人</label><div class="field-value">{{ drillOrder.contactPerson }}</div></div>
|
||||||
|
<div class="form-field"><label>联系电话</label><div class="field-value">{{ drillOrder.contactWay }}</div></div>
|
||||||
|
<div class="form-field"><label>交货日期</label><div class="field-value">{{ drillOrder.deliveryDate }}</div></div>
|
||||||
|
<div class="form-field"><label>合同号</label><div class="field-value">{{ drillOrder.contractCode }}</div></div>
|
||||||
|
<div class="form-field" style="grid-column:1/3;"><label>备注</label><div class="field-value">{{ drillOrder.remark }}</div></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div v-else>
|
||||||
|
<el-empty description="未找到订单信息" />
|
||||||
|
</div>
|
||||||
|
</el-dialog>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import { listRequirement } from '@/api/aps/requirement'
|
||||||
|
import { getCrmOrderInfo } from '@/api/aps/schedule'
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: 'ApsSchedule',
|
||||||
|
data() {
|
||||||
|
const today = new Date()
|
||||||
|
const y = today.getFullYear()
|
||||||
|
const m = String(today.getMonth() + 1).padStart(2, '0')
|
||||||
|
const d = String(today.getDate()).padStart(2, '0')
|
||||||
|
return {
|
||||||
|
queryDate: `${y}-${m}-${d}`,
|
||||||
|
schLoading: false,
|
||||||
|
hasQueried: false,
|
||||||
|
scheduleList: [],
|
||||||
|
detailList: [],
|
||||||
|
summaryText: '',
|
||||||
|
drillDialogVisible: false,
|
||||||
|
drillOrder: null
|
||||||
|
}
|
||||||
|
},
|
||||||
|
created() {
|
||||||
|
this.handleQuery()
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
handleDateChange() {
|
||||||
|
this.handleQuery()
|
||||||
|
},
|
||||||
|
handleQuery() {
|
||||||
|
if (!this.queryDate) {
|
||||||
|
this.$message.warning('请选择生产日期')
|
||||||
|
return
|
||||||
|
}
|
||||||
|
this.schLoading = true
|
||||||
|
this.hasQueried = true
|
||||||
|
this.detailList = []
|
||||||
|
this.scheduleList = []
|
||||||
|
|
||||||
|
// 后端 list 接口已通过 fillDetailList 填充 detailList
|
||||||
|
listRequirement({ prodDate: this.queryDate, pageNum: 1, pageSize: 999 }).then(res => {
|
||||||
|
const list = res.rows || []
|
||||||
|
this.scheduleList = list
|
||||||
|
|
||||||
|
// 扁平化所有 detailList
|
||||||
|
const merged = []
|
||||||
|
list.forEach(sch => {
|
||||||
|
const details = sch.detailList || []
|
||||||
|
details.forEach(d => {
|
||||||
|
merged.push({
|
||||||
|
...d,
|
||||||
|
scheduleNo: sch.scheduleNo,
|
||||||
|
customerName: sch.customerName,
|
||||||
|
businessUser: sch.businessUser,
|
||||||
|
deliveryCycle: sch.deliveryCycle,
|
||||||
|
_scheduleId: sch.scheduleId
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
|
this.detailList = merged
|
||||||
|
|
||||||
|
const totalWeight = merged.reduce((sum, d) => sum + (parseFloat(d.scheduleWeight) || 0), 0)
|
||||||
|
this.summaryText = `共 ${list.length} 个产需单,${merged.length} 条明细,排产总吨数 ${totalWeight.toFixed(3)} 吨`
|
||||||
|
}).catch(() => {
|
||||||
|
this.detailList = []
|
||||||
|
this.summaryText = ''
|
||||||
|
}).finally(() => {
|
||||||
|
this.schLoading = false
|
||||||
|
})
|
||||||
|
},
|
||||||
|
|
||||||
|
handleRowClick(row) {
|
||||||
|
// 通过 _scheduleId 找到产需单,然后找到关联的订单
|
||||||
|
const sch = this.scheduleList.find(s => s.scheduleId === row._scheduleId)
|
||||||
|
if (!sch || !sch.orderList || sch.orderList.length === 0) {
|
||||||
|
this.$message.warning('未找到关联订单')
|
||||||
|
return
|
||||||
|
}
|
||||||
|
// 取第一个关联订单展示
|
||||||
|
const order = sch.orderList[0]
|
||||||
|
getCrmOrderInfo(order.orderId).then(res => {
|
||||||
|
this.drillOrder = res.data
|
||||||
|
this.drillDialogVisible = true
|
||||||
|
}).catch(() => {
|
||||||
|
this.$message.warning('未找到来源订单')
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped lang="scss">
|
||||||
|
@import './scss/aps-theme.scss';
|
||||||
|
|
||||||
|
.aps-sch-page {
|
||||||
|
height: 100%;
|
||||||
|
padding: 8px;
|
||||||
|
box-sizing: border-box;
|
||||||
|
background: $aps-bg;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 工具栏
|
||||||
|
.aps-sch-toolbar {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 10px;
|
||||||
|
padding: 10px 16px;
|
||||||
|
background: $aps-white;
|
||||||
|
border: 1px solid $aps-border;
|
||||||
|
border-radius: $aps-radius;
|
||||||
|
box-shadow: $aps-shadow-sm;
|
||||||
|
flex-shrink: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.aps-sch-label {
|
||||||
|
font-size: 13px;
|
||||||
|
font-weight: 600;
|
||||||
|
color: $aps-text;
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
.aps-sch-summary {
|
||||||
|
margin-left: auto;
|
||||||
|
font-size: 12px;
|
||||||
|
color: $aps-text-muted;
|
||||||
|
background: $aps-silver-1;
|
||||||
|
padding: 4px 12px;
|
||||||
|
border-radius: $aps-radius;
|
||||||
|
border: 1px solid $aps-border;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 排产卡片
|
||||||
|
.aps-sch-card {
|
||||||
|
flex: 1;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
min-height: 0;
|
||||||
|
overflow: hidden;
|
||||||
|
|
||||||
|
.detail-card-body {
|
||||||
|
flex: 1;
|
||||||
|
overflow: auto;
|
||||||
|
min-height: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 表格
|
||||||
|
.aps-table {
|
||||||
|
width: 100%;
|
||||||
|
|
||||||
|
::v-deep th {
|
||||||
|
background: $aps-silver-1 !important;
|
||||||
|
color: $aps-text !important;
|
||||||
|
font-weight: 600 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
::v-deep .el-table__body tr:hover > td {
|
||||||
|
background-color: $aps-red-1 !important;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
::v-deep td {
|
||||||
|
padding: 6px 8px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.sch-link-text {
|
||||||
|
color: $aps-red-2;
|
||||||
|
font-weight: 500;
|
||||||
|
&:hover {
|
||||||
|
color: $aps-red-3;
|
||||||
|
text-decoration: underline;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 复用卡片/网格变量
|
||||||
|
.aps-btn-red {
|
||||||
|
@include aps-btn-red;
|
||||||
|
}
|
||||||
|
|
||||||
|
.detail-card {
|
||||||
|
background: $aps-white;
|
||||||
|
border: 1px solid $aps-border;
|
||||||
|
border-radius: $aps-radius;
|
||||||
|
box-shadow: $aps-shadow-sm;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
.detail-card-header {
|
||||||
|
background: linear-gradient(to right, $aps-red-2, $aps-red-3);
|
||||||
|
color: white;
|
||||||
|
padding: 8px 14px;
|
||||||
|
font-size: 13px;
|
||||||
|
font-weight: 600;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: space-between;
|
||||||
|
}
|
||||||
|
|
||||||
|
.detail-card-body {
|
||||||
|
padding: 14px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.form-grid-2 {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: repeat(2, 1fr);
|
||||||
|
gap: 10px 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.form-field {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 3px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.form-field label {
|
||||||
|
font-size: 11px;
|
||||||
|
color: $aps-text-muted;
|
||||||
|
font-weight: 500;
|
||||||
|
}
|
||||||
|
|
||||||
|
.form-field .field-value {
|
||||||
|
font-size: 13px;
|
||||||
|
color: $aps-text;
|
||||||
|
padding: 4px 0;
|
||||||
|
border-bottom: 1px solid $aps-silver-mid;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
143
klp-ui/src/views/wms/post/aps/scss/aps-theme.scss
Normal file
143
klp-ui/src/views/wms/post/aps/scss/aps-theme.scss
Normal file
@@ -0,0 +1,143 @@
|
|||||||
|
// ============================================
|
||||||
|
// APS 排产管理模块 — 银灰色 + 红色主题
|
||||||
|
// 每个页面通过 @import 引入并提供 scoped 命名空间
|
||||||
|
// ============================================
|
||||||
|
|
||||||
|
// ——— 颜色变量 ———
|
||||||
|
$aps-silver-1: #f5f5f5; // 最浅银灰(背景)
|
||||||
|
$aps-silver-2: #e8e8e8; // 浅银灰(卡片/列表行)
|
||||||
|
$aps-silver-3: #d9d9d9; // 中银灰(边框)
|
||||||
|
$aps-silver-4: #8c8c8c; // 深银灰(次要文字/图标)
|
||||||
|
$aps-silver-5: #595959; // 最深银灰(主标题/强调文字)
|
||||||
|
|
||||||
|
$aps-red-1: #fff1f0; // 极浅红(背景高亮)
|
||||||
|
$aps-red-2: #ff4d4f; // 标准红(主按钮/标签)
|
||||||
|
$aps-red-3: #cf1322; // 深红(hover/边框强调)
|
||||||
|
$aps-red-4: #f5222d; // 辅助红
|
||||||
|
|
||||||
|
// ——— 混入:列表项 ———
|
||||||
|
@mixin aps-list-item {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
padding: 10px 12px;
|
||||||
|
margin-bottom: 6px;
|
||||||
|
border: 1px solid $aps-silver-3;
|
||||||
|
background-color: #fff;
|
||||||
|
cursor: pointer;
|
||||||
|
transition: all 0.2s ease;
|
||||||
|
border-radius: 4px;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
border-color: $aps-red-2;
|
||||||
|
background-color: $aps-red-1;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.active {
|
||||||
|
border-left: 3px solid $aps-red-2;
|
||||||
|
border-color: $aps-red-2;
|
||||||
|
background-color: $aps-red-1;
|
||||||
|
box-shadow: 0 0 0 1px rgba($aps-red-2, 0.08) inset;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ——— 混入:银色卡片 ———
|
||||||
|
@mixin aps-card {
|
||||||
|
background: #fff;
|
||||||
|
border: 1px solid $aps-silver-3;
|
||||||
|
border-radius: 6px;
|
||||||
|
padding: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ——— 混入:银色按钮变体 ———
|
||||||
|
@mixin aps-btn-silver {
|
||||||
|
color: $aps-silver-5;
|
||||||
|
background: $aps-silver-1;
|
||||||
|
border-color: $aps-silver-3;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
color: $aps-red-2;
|
||||||
|
border-color: $aps-red-2;
|
||||||
|
background: $aps-red-1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ——— 混入:红色按钮变体 ———
|
||||||
|
@mixin aps-btn-red {
|
||||||
|
color: #fff;
|
||||||
|
background: $aps-red-2;
|
||||||
|
border-color: $aps-red-2;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
background: $aps-red-3;
|
||||||
|
border-color: $aps-red-3;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ——— 混入:状态标签 ———
|
||||||
|
@mixin aps-status-tag($bg, $color) {
|
||||||
|
display: inline-block;
|
||||||
|
padding: 2px 8px;
|
||||||
|
border-radius: 3px;
|
||||||
|
font-size: 12px;
|
||||||
|
background: $bg;
|
||||||
|
color: $color;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ——— 详情卡片通用变量(参照 HTML 设计稿) ———
|
||||||
|
$aps-bg: #f4f5f7;
|
||||||
|
$aps-white: #ffffff;
|
||||||
|
$aps-border: #c8cdd2;
|
||||||
|
$aps-text: #2c3e50;
|
||||||
|
$aps-text-muted: #7f8c8d;
|
||||||
|
$aps-silver-mid: #d5d8dc;
|
||||||
|
$aps-shadow-sm: 0 1px 4px rgba(0,0,0,0.08);
|
||||||
|
$aps-radius: 4px;
|
||||||
|
|
||||||
|
// ——— 混入:详情卡片 ———
|
||||||
|
@mixin aps-detail-card {
|
||||||
|
background: $aps-white;
|
||||||
|
border: 1px solid $aps-border;
|
||||||
|
border-radius: $aps-radius;
|
||||||
|
box-shadow: $aps-shadow-sm;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ——— 混入:卡片头部渐变 ———
|
||||||
|
@mixin aps-card-header {
|
||||||
|
background: linear-gradient(to right, $aps-red-2, $aps-red-3);
|
||||||
|
color: white;
|
||||||
|
padding: 8px 14px;
|
||||||
|
font-size: 13px;
|
||||||
|
font-weight: 600;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: space-between;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ——— 混入:表单网格(2列) ———
|
||||||
|
@mixin aps-form-grid-2 {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: repeat(2, 1fr);
|
||||||
|
gap: 10px 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ——— 混入:表单字段 ———
|
||||||
|
@mixin aps-form-field {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 3px;
|
||||||
|
|
||||||
|
label {
|
||||||
|
font-size: 11px;
|
||||||
|
color: $aps-text-muted;
|
||||||
|
font-weight: 500;
|
||||||
|
}
|
||||||
|
|
||||||
|
.field-value {
|
||||||
|
font-size: 13px;
|
||||||
|
color: $aps-text;
|
||||||
|
padding: 4px 0;
|
||||||
|
border-bottom: 1px solid $aps-silver-mid;
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user