feat(erp): 采购计划/采购审核/到货跟踪 + 供应商管理
- 采购计划:选合同自动带出明细、合同/供应商表格选择器、批量填充(可生成N行)、卷号/数量列、送审/重新送审流程 - 采购审核:通过/驳回 + 申请意见,每次审核留痕(erp_purchase_plan_audit_log),计划详情展示审核历史/驳回理由 - 到货跟踪:上传到货Excel按牌号+规格回填明细到货量与状态,列校验/kg→t纠正,满额自动归档 - 供应商管理页(复用既有 erp_supplier 后端) - 综合搜索(计划号/供货商/合同号)、左右分栏工作台、全局表单按钮对齐修复 - 清理无用旧 erp 页面(看板/需求/订单/收货/退货/汇总) - DDL 与菜单脚本:docs/purchase-plan-ddl.sql(按 path 解析父目录、可重复执行) Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
894
klp-ui/src/views/erp/purchasePlan/index.vue
Normal file
894
klp-ui/src/views/erp/purchasePlan/index.vue
Normal file
@@ -0,0 +1,894 @@
|
||||
<template>
|
||||
<div class="pp-wb">
|
||||
<div class="pp-main">
|
||||
<!-- 左:计划列表 -->
|
||||
<aside class="pp-col pp-plans">
|
||||
<div class="pp-col-tool">
|
||||
<el-input
|
||||
v-model="queryParams.keyword"
|
||||
size="small"
|
||||
clearable
|
||||
placeholder="搜索计划号 / 供货商 / 合同号"
|
||||
prefix-icon="el-icon-search"
|
||||
@keyup.enter.native="handleQuery"
|
||||
@clear="handleQuery"
|
||||
/>
|
||||
<el-button type="primary" size="small" icon="el-icon-plus" @click="handleAdd" v-hasPermi="['erp:purchasePlan:add']">新增</el-button>
|
||||
</div>
|
||||
<div class="pp-col-filter">
|
||||
<el-radio-group v-model="queryParams.auditStatus" size="mini" @change="handleQuery">
|
||||
<el-radio-button label="">全部</el-radio-button>
|
||||
<el-radio-button label="3">待送审</el-radio-button>
|
||||
<el-radio-button label="0">待审</el-radio-button>
|
||||
<el-radio-button label="1">通过</el-radio-button>
|
||||
<el-radio-button label="2">驳回</el-radio-button>
|
||||
</el-radio-group>
|
||||
</div>
|
||||
<ul class="pp-list" v-loading="loading">
|
||||
<li
|
||||
v-for="p in planList"
|
||||
:key="p.planId"
|
||||
class="pp-li"
|
||||
:class="{ active: mode !== 'edit' && current.planId === p.planId }"
|
||||
@click="selectPlan(p)"
|
||||
>
|
||||
<div class="pp-li-r1">
|
||||
<span class="pp-no">{{ p.planNo }}</span>
|
||||
<span class="pp-badge" :class="'a' + p.auditStatus">{{ auditText(p.auditStatus) }}</span>
|
||||
</div>
|
||||
<div class="pp-li-r2">
|
||||
<span>{{ p.supplier || '—' }}</span>
|
||||
<span class="pp-w">{{ p.planWeight }} T</span>
|
||||
</div>
|
||||
<el-progress :percentage="Number(p.progress) || 0" :stroke-width="4" :show-text="false" :color="progressColor" />
|
||||
<div class="pp-li-r3">
|
||||
<span>{{ p.purchaseDate || '未排期' }}</span>
|
||||
<span>{{ (Number(p.progress) || 0).toFixed(0) }}%<i v-if="p.planStatus === '1'" class="pp-arch">已归档</i></span>
|
||||
</div>
|
||||
</li>
|
||||
<li v-if="!loading && !planList.length" class="pp-empty">暂无采购计划</li>
|
||||
</ul>
|
||||
<pagination
|
||||
v-show="total > 0"
|
||||
:total="total"
|
||||
:page.sync="queryParams.pageNum"
|
||||
:limit.sync="queryParams.pageSize"
|
||||
:pager-count="5"
|
||||
layout="prev, pager, next"
|
||||
@pagination="getList"
|
||||
/>
|
||||
</aside>
|
||||
|
||||
<!-- 右:详情 / 编辑 -->
|
||||
<section class="pp-col pp-detail">
|
||||
<div v-if="mode === 'empty'" class="pp-placeholder">
|
||||
<i class="el-icon-tickets"></i>
|
||||
<p>从左侧选择一条采购计划,或点击「新增」按销售合同创建</p>
|
||||
</div>
|
||||
|
||||
<!-- 编辑 / 新增 -->
|
||||
<div v-else-if="mode === 'edit'" class="pp-edit">
|
||||
<div class="pp-d-head">
|
||||
<span class="pp-d-title">{{ form.planId ? '编辑采购计划' : '新增采购计划' }}</span>
|
||||
<div>
|
||||
<el-button size="small" @click="cancelEdit">取消</el-button>
|
||||
<el-button size="small" type="primary" :loading="buttonLoading" @click="submitForm">保存</el-button>
|
||||
</div>
|
||||
</div>
|
||||
<el-form :model="form" :rules="rules" ref="form" label-width="80px" class="pp-form" size="small">
|
||||
<div class="pp-section">基本信息</div>
|
||||
<el-row :gutter="16">
|
||||
<el-col :span="12">
|
||||
<el-form-item label="计划号" prop="planNo">
|
||||
<el-input v-model="form.planNo" placeholder="留空自动生成" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="采购日期" prop="purchaseDate">
|
||||
<el-date-picker v-model="form.purchaseDate" type="date" value-format="yyyy-MM-dd" style="width:100%" placeholder="选择日期" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
|
||||
<div class="pp-section">
|
||||
销售合同
|
||||
<el-button type="primary" plain size="mini" icon="el-icon-plus" class="pp-section-act" @click="openContractPicker">选择合同</el-button>
|
||||
<span class="pp-section-hint" v-if="form.orderIds.length">已选 {{ form.orderIds.length }} 个合同</span>
|
||||
</div>
|
||||
<div class="pp-picked">
|
||||
<template v-if="selectedContracts.length">
|
||||
<span class="pp-chip" v-for="c in selectedContracts" :key="c.orderId">
|
||||
<b>{{ c.orderCode }}</b><span class="pp-chip-sub">{{ c.contractName }} · {{ c.customer }}</span>
|
||||
<i class="el-icon-close" @click="removeContract(c.orderId)" />
|
||||
</span>
|
||||
</template>
|
||||
<template v-else-if="form.contractCodes && form.contractCodes.length">
|
||||
<span class="pp-chip readonly" v-for="code in form.contractCodes" :key="code">{{ code }}</span>
|
||||
<span class="pp-chip-tip">点「选择合同」可修改</span>
|
||||
</template>
|
||||
<span v-else class="pp-picked-empty">未选择销售合同</span>
|
||||
</div>
|
||||
|
||||
<div class="pp-section">
|
||||
采购明细
|
||||
<el-button type="text" size="mini" icon="el-icon-plus" class="pp-section-act" @click="addItem">加行</el-button>
|
||||
<el-button type="text" size="mini" icon="el-icon-magic-stick" class="pp-section-act" @click="openBatchFill">批量填充</el-button>
|
||||
<span class="pp-section-hint" v-if="form.items.length">共 {{ form.items.length }} 行 · 计 {{ itemsWeight }} T</span>
|
||||
</div>
|
||||
<el-table :data="form.items" border size="mini" max-height="300">
|
||||
<el-table-column label="#" type="index" width="40" align="center" />
|
||||
<el-table-column label="产品" min-width="70">
|
||||
<template slot-scope="s"><el-input v-model="s.row.productType" size="mini" placeholder="热轧卷板" /></template>
|
||||
</el-table-column>
|
||||
<el-table-column label="材质" min-width="80">
|
||||
<template slot-scope="s"><el-input v-model="s.row.material" size="mini" /></template>
|
||||
</el-table-column>
|
||||
<el-table-column label="牌号" min-width="75">
|
||||
<template slot-scope="s"><el-input v-model="s.row.grade" size="mini" /></template>
|
||||
</el-table-column>
|
||||
<el-table-column label="卷号" min-width="95">
|
||||
<template slot-scope="s"><el-input v-model="s.row.coilNo" size="mini" /></template>
|
||||
</el-table-column>
|
||||
<el-table-column label="宽度" min-width="75">
|
||||
<template slot-scope="s"><el-input v-model="s.row.width" size="mini" /></template>
|
||||
</el-table-column>
|
||||
<el-table-column label="厚度" min-width="75">
|
||||
<template slot-scope="s"><el-input v-model="s.row.thickness" size="mini" /></template>
|
||||
</el-table-column>
|
||||
<el-table-column label="宽公差" min-width="75">
|
||||
<template slot-scope="s"><el-input v-model="s.row.widthTolerance" size="mini" /></template>
|
||||
</el-table-column>
|
||||
<el-table-column label="厚公差" min-width="75">
|
||||
<template slot-scope="s"><el-input v-model="s.row.thicknessTolerance" size="mini" /></template>
|
||||
</el-table-column>
|
||||
<el-table-column label="重量(T)" min-width="80">
|
||||
<template slot-scope="s"><el-input v-model="s.row.weight" size="mini" /></template>
|
||||
</el-table-column>
|
||||
<el-table-column label="数量" min-width="65">
|
||||
<template slot-scope="s"><el-input v-model="s.row.quantity" size="mini" /></template>
|
||||
</el-table-column>
|
||||
<el-table-column label="供货商" min-width="90">
|
||||
<template slot-scope="s"><el-input v-model="s.row.supplier" size="mini" /></template>
|
||||
</el-table-column>
|
||||
<el-table-column label="操作" width="64" align="center" fixed="right">
|
||||
<template slot-scope="s">
|
||||
<i class="el-icon-document-copy pp-copy" title="复制此行" @click="copyItem(s.$index)" />
|
||||
<i class="el-icon-delete pp-del" title="删除" @click="removeItem(s.$index)" />
|
||||
</template>
|
||||
</el-table-column>
|
||||
<template slot="empty"><span>点「加行」添加,或在上方选择销售合同载入明细</span></template>
|
||||
</el-table>
|
||||
|
||||
<el-form-item label="备注" prop="remark" style="margin-top:14px">
|
||||
<el-input type="textarea" v-model="form.remark" :rows="2" placeholder="请输入备注" />
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</div>
|
||||
|
||||
<!-- 查看 -->
|
||||
<div v-else class="pp-view">
|
||||
<div class="pp-d-head">
|
||||
<div>
|
||||
<span class="pp-d-title">{{ current.planNo }}</span>
|
||||
<span class="pp-badge" :class="'a' + current.auditStatus">{{ auditText(current.auditStatus) }}</span>
|
||||
<span class="pp-badge plan" :class="current.planStatus === '1' ? 'p1' : 'p0'">{{ current.planStatus === '1' ? '已归档' : '进行中' }}</span>
|
||||
</div>
|
||||
<div>
|
||||
<el-button
|
||||
v-if="current.auditStatus === '3' || current.auditStatus === '2'"
|
||||
size="small" type="primary" icon="el-icon-s-promotion"
|
||||
:loading="submitLoading" @click="submitForAudit"
|
||||
v-hasPermi="['erp:purchasePlan:edit']"
|
||||
>{{ current.auditStatus === '2' ? '重新送审' : '送审' }}</el-button>
|
||||
<el-button size="small" icon="el-icon-edit" @click="handleEdit" v-hasPermi="['erp:purchasePlan:edit']">编辑</el-button>
|
||||
<el-button size="small" type="danger" plain icon="el-icon-delete" @click="handleDelete(current)" v-hasPermi="['erp:purchasePlan:remove']">删除</el-button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="pp-meta">
|
||||
<div class="pp-meta-i"><label>供货商</label><span>{{ current.supplier || '—' }}</span></div>
|
||||
<div class="pp-meta-i"><label>采购日期</label><span>{{ current.purchaseDate || '—' }}</span></div>
|
||||
<div class="pp-meta-i"><label>关联合同</label><span>{{ (current.contractCodes || []).join('、') || '—' }}</span></div>
|
||||
<div class="pp-meta-i"><label>计划重量</label><span>{{ current.planWeight }} T</span></div>
|
||||
<div class="pp-meta-i"><label>已到货</label><span>{{ current.arrivedWeight }} T</span></div>
|
||||
<div class="pp-meta-i wide">
|
||||
<label>到货进度</label>
|
||||
<el-progress
|
||||
:percentage="Number(current.progress) || 0"
|
||||
:stroke-width="10" :text-inside="true" :color="progressColor"
|
||||
:format="p => p.toFixed(1) + '%'"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="pp-audit" v-if="(current.auditLogs && current.auditLogs.length) || current.auditOpinion">
|
||||
<div class="pp-audit-head">审核记录</div>
|
||||
<ul class="pp-audit-list" v-if="current.auditLogs && current.auditLogs.length">
|
||||
<li v-for="(log, i) in current.auditLogs" :key="i">
|
||||
<span class="pp-badge" :class="'a' + log.auditStatus">{{ auditText(log.auditStatus) }}</span>
|
||||
<span class="pp-audit-by">{{ log.auditor || '—' }}</span>
|
||||
<span class="pp-audit-time">{{ log.auditTime }}</span>
|
||||
<span class="pp-audit-op">{{ log.auditOpinion || '(无意见)' }}</span>
|
||||
</li>
|
||||
</ul>
|
||||
<div v-else class="pp-audit-op single">
|
||||
<span class="pp-badge" :class="'a' + current.auditStatus">{{ auditText(current.auditStatus) }}</span>
|
||||
{{ current.auditOpinion || '—' }}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<el-tabs v-model="activeTab" class="pp-tabs">
|
||||
<el-tab-pane label="采购明细" name="items">
|
||||
<el-table :data="current.items" border size="mini" max-height="340">
|
||||
<el-table-column label="#" type="index" width="40" align="center" />
|
||||
<el-table-column label="产品" prop="productType" min-width="70" show-overflow-tooltip />
|
||||
<el-table-column label="材质" prop="material" min-width="80" show-overflow-tooltip />
|
||||
<el-table-column label="牌号" prop="grade" min-width="75" />
|
||||
<el-table-column label="卷号" prop="coilNo" min-width="95" show-overflow-tooltip />
|
||||
<el-table-column label="宽度" prop="width" min-width="70" />
|
||||
<el-table-column label="厚度" prop="thickness" min-width="70" />
|
||||
<el-table-column label="重量(T)" prop="weight" min-width="78" align="right" />
|
||||
<el-table-column label="数量" prop="quantity" min-width="60" align="right" />
|
||||
<el-table-column label="已到货(T)" prop="arrivedWeight" min-width="82" align="right" />
|
||||
<el-table-column label="到货状态" min-width="84" align="center">
|
||||
<template slot-scope="s">
|
||||
<span class="pp-istat" :class="'s' + (s.row.itemStatus || '0')">{{ itemStatusText(s.row.itemStatus) }}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="供货商" prop="supplier" min-width="90" show-overflow-tooltip />
|
||||
<template slot="empty"><span>无明细</span></template>
|
||||
</el-table>
|
||||
</el-tab-pane>
|
||||
|
||||
<el-tab-pane label="到货进度" name="delivery">
|
||||
<div class="pp-deliv-bar">
|
||||
<span class="pp-deliv-tip" v-if="current.auditStatus !== '1'">审核通过后才能上传到货 Excel</span>
|
||||
<el-upload
|
||||
v-else
|
||||
:headers="upload.headers"
|
||||
:action="uploadUrl"
|
||||
:show-file-list="false"
|
||||
accept=".xlsx,.xls"
|
||||
:on-success="handleUploadSuccess"
|
||||
:on-error="handleUploadError"
|
||||
>
|
||||
<el-button type="primary" size="small" icon="el-icon-upload2">上传到货 Excel</el-button>
|
||||
</el-upload>
|
||||
<span class="pp-deliv-hint">上传后按牌号+规格回填明细到货量与状态</span>
|
||||
</div>
|
||||
<el-table :data="deliveryList" border stripe size="mini" max-height="340" v-loading="deliveryLoading">
|
||||
<el-table-column label="日期" prop="arrivalDate" width="100" align="center" />
|
||||
<el-table-column label="牌号" prop="grade" width="80" align="center" />
|
||||
<el-table-column label="规格" prop="spec" width="110" align="center" />
|
||||
<el-table-column label="卷号" prop="coilNo" width="110" align="center" />
|
||||
<el-table-column label="单卷(T)" prop="coilWeight" width="80" align="right" />
|
||||
<el-table-column label="车号" prop="truckNo" width="100" align="center" />
|
||||
<el-table-column label="整车(T)" prop="truckWeight" width="80" align="right" />
|
||||
<el-table-column label="件数" prop="pieceCount" width="56" align="center" />
|
||||
<el-table-column label="销售" prop="salesCode" width="85" align="center" />
|
||||
<el-table-column label="到站" prop="arrivalStation" width="90" align="center" />
|
||||
<el-table-column label="" width="36" align="center">
|
||||
<template slot-scope="s"><i class="el-icon-delete pp-del" @click="removeDelivery(s.row)" /></template>
|
||||
</el-table-column>
|
||||
<template slot="empty"><span>暂无到货记录</span></template>
|
||||
</el-table>
|
||||
</el-tab-pane>
|
||||
</el-tabs>
|
||||
</div>
|
||||
</section>
|
||||
</div>
|
||||
|
||||
<!-- 选择销售合同:完整信息表格 + 多选 -->
|
||||
<el-dialog title="选择销售合同" :visible.sync="pickerOpen" width="900px" append-to-body>
|
||||
<div class="pp-picker-tool">
|
||||
<el-input
|
||||
v-model="pickerQuery.keyword"
|
||||
size="small"
|
||||
clearable
|
||||
placeholder="搜索合同号 / 合同名称 / 客户"
|
||||
prefix-icon="el-icon-search"
|
||||
style="width:280px"
|
||||
@keyup.enter.native="reloadPicker"
|
||||
@clear="reloadPicker"
|
||||
/>
|
||||
<el-button type="primary" size="small" icon="el-icon-search" @click="reloadPicker">查询</el-button>
|
||||
</div>
|
||||
<el-table
|
||||
ref="pickerTable"
|
||||
:data="pickerList"
|
||||
v-loading="pickerLoading"
|
||||
border size="small"
|
||||
max-height="420"
|
||||
@selection-change="onPickerSelection"
|
||||
row-key="orderId"
|
||||
>
|
||||
<el-table-column type="selection" width="46" reserve-selection />
|
||||
<el-table-column label="订单编号" prop="orderCode" width="150" show-overflow-tooltip />
|
||||
<el-table-column label="合同号" prop="contractCode" width="130" show-overflow-tooltip />
|
||||
<el-table-column label="合同名称" prop="contractName" min-width="140" show-overflow-tooltip />
|
||||
<el-table-column label="客户(需方)" prop="customer" min-width="160" show-overflow-tooltip />
|
||||
<el-table-column label="销售员" prop="salesman" width="90" />
|
||||
<el-table-column label="金额" prop="orderAmount" width="100" align="right" />
|
||||
<el-table-column label="已有计划" prop="planCount" width="80" align="center">
|
||||
<template slot-scope="s"><span :class="{ 'pp-cnt-zero': !s.row.planCount }">{{ s.row.planCount || 0 }}</span></template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
<pagination
|
||||
v-show="pickerTotal > 0"
|
||||
:total="pickerTotal"
|
||||
:page.sync="pickerQuery.pageNum"
|
||||
:limit.sync="pickerQuery.pageSize"
|
||||
@pagination="loadPicker"
|
||||
/>
|
||||
<div slot="footer">
|
||||
<span class="pp-picker-count">已选 {{ pickerSelection.length }} 个合同</span>
|
||||
<el-button @click="pickerOpen = false">取消</el-button>
|
||||
<el-button type="primary" @click="confirmPicker">确定</el-button>
|
||||
</div>
|
||||
</el-dialog>
|
||||
|
||||
<!-- 选择供应商:表格 + 单选 -->
|
||||
<el-dialog title="选择供应商" :visible.sync="supplierPickerOpen" width="760px" append-to-body>
|
||||
<div class="pp-picker-tool">
|
||||
<el-input
|
||||
v-model="supplierQuery.name"
|
||||
size="small"
|
||||
clearable
|
||||
placeholder="搜索供应商名称"
|
||||
prefix-icon="el-icon-search"
|
||||
style="width:260px"
|
||||
@keyup.enter.native="reloadSuppliers"
|
||||
@clear="reloadSuppliers"
|
||||
/>
|
||||
<el-button type="primary" size="small" icon="el-icon-search" @click="reloadSuppliers">查询</el-button>
|
||||
</div>
|
||||
<el-table :data="supplierList" v-loading="supplierLoading" border size="small" max-height="420" @row-click="chooseSupplier">
|
||||
<el-table-column label="编码" prop="supplierCode" width="130" show-overflow-tooltip />
|
||||
<el-table-column label="供应商名称" prop="name" min-width="180" show-overflow-tooltip />
|
||||
<el-table-column label="类型" prop="type" width="90" align="center" />
|
||||
<el-table-column label="信用" prop="creditRating" width="70" align="center" />
|
||||
<el-table-column label="联系人" prop="contactPerson" width="100" />
|
||||
<el-table-column label="电话" prop="contactPhone" width="130" />
|
||||
<el-table-column label="操作" width="70" align="center">
|
||||
<template slot-scope="s"><el-button type="text" size="mini" @click.stop="chooseSupplier(s.row)">选择</el-button></template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
<pagination
|
||||
v-show="supplierTotal > 0"
|
||||
:total="supplierTotal"
|
||||
:page.sync="supplierQuery.pageNum"
|
||||
:limit.sync="supplierQuery.pageSize"
|
||||
@pagination="loadSuppliers"
|
||||
/>
|
||||
</el-dialog>
|
||||
|
||||
<!-- 批量填充明细:设一次,一键填满所有行(留空不覆盖) -->
|
||||
<el-dialog title="批量填充明细" :visible.sync="batchFillOpen" width="560px" append-to-body>
|
||||
<p class="pp-batch-tip">下面填了值的字段会写入<b>全部明细行</b>,留空的不覆盖。常用于整批同产品/材质/规格。</p>
|
||||
<el-form :model="batchFill" label-width="72px" size="small">
|
||||
<el-row :gutter="14">
|
||||
<el-col :span="12"><el-form-item label="产品"><el-input v-model="batchFill.productType" placeholder="如 热轧卷板" /></el-form-item></el-col>
|
||||
<el-col :span="12"><el-form-item label="材质"><el-input v-model="batchFill.material" /></el-form-item></el-col>
|
||||
<el-col :span="12"><el-form-item label="牌号"><el-input v-model="batchFill.grade" /></el-form-item></el-col>
|
||||
<el-col :span="12"><el-form-item label="卷号"><el-input v-model="batchFill.coilNo" /></el-form-item></el-col>
|
||||
<el-col :span="12"><el-form-item label="宽度"><el-input v-model="batchFill.width" /></el-form-item></el-col>
|
||||
<el-col :span="12"><el-form-item label="厚度"><el-input v-model="batchFill.thickness" /></el-form-item></el-col>
|
||||
<el-col :span="12"><el-form-item label="宽公差"><el-input v-model="batchFill.widthTolerance" /></el-form-item></el-col>
|
||||
<el-col :span="12"><el-form-item label="厚公差"><el-input v-model="batchFill.thicknessTolerance" /></el-form-item></el-col>
|
||||
<el-col :span="12"><el-form-item label="重量(T)"><el-input v-model="batchFill.weight" /></el-form-item></el-col>
|
||||
<el-col :span="12"><el-form-item label="数量"><el-input v-model="batchFill.quantity" /></el-form-item></el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="供货商">
|
||||
<div class="pp-inline-pick">
|
||||
<el-input v-model="batchFill.supplier" placeholder="选择或输入" />
|
||||
<el-button icon="el-icon-search" @click="openSupplierPicker">选择</el-button>
|
||||
</div>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</el-form>
|
||||
<div slot="footer" class="pp-batch-footer">
|
||||
<el-checkbox v-model="batchFillNewRow">设为「加行」默认值</el-checkbox>
|
||||
<span class="pp-batch-gen">生成 <el-input v-model="batchRows" size="mini" style="width:64px" /> 行</span>
|
||||
<el-button @click="batchFillOpen = false">取消</el-button>
|
||||
<el-button @click="applyBatchFill">应用到现有行</el-button>
|
||||
<el-button type="primary" @click="generateRows">生成行并填充</el-button>
|
||||
</div>
|
||||
</el-dialog>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import {
|
||||
listPurchasePlan,
|
||||
purchasePlanStatistics,
|
||||
getPurchasePlan,
|
||||
getItemsByOrders,
|
||||
addPurchasePlan,
|
||||
updatePurchasePlan,
|
||||
delPurchasePlan,
|
||||
submitPurchasePlan,
|
||||
listDelivery,
|
||||
delDelivery,
|
||||
listContracts
|
||||
} from '@/api/erp/purchasePlan'
|
||||
import { listSupplier } from '@/api/erp/purchase'
|
||||
import { getToken } from '@/utils/auth'
|
||||
|
||||
export default {
|
||||
name: 'ErpPurchasePlan',
|
||||
data() {
|
||||
return {
|
||||
loading: true,
|
||||
total: 0,
|
||||
planList: [],
|
||||
stats: { total: 0, completed: 0 },
|
||||
queryParams: { pageNum: 1, pageSize: 20, keyword: undefined, auditStatus: '' },
|
||||
mode: 'empty', // empty | view | edit
|
||||
current: {},
|
||||
activeTab: 'items',
|
||||
form: {},
|
||||
rules: {},
|
||||
buttonLoading: false,
|
||||
submitLoading: false,
|
||||
selectedContracts: [],
|
||||
// 批量填充
|
||||
batchFillOpen: false,
|
||||
batchFillNewRow: true,
|
||||
batchRows: 0,
|
||||
batchFill: { productType: '热轧卷板', material: '', grade: '', coilNo: '', width: '', thickness: '', widthTolerance: '', thicknessTolerance: '', weight: '', quantity: '', supplier: '' },
|
||||
newRowDefaults: null,
|
||||
// 合同选择器
|
||||
pickerOpen: false,
|
||||
pickerLoading: false,
|
||||
pickerList: [],
|
||||
pickerTotal: 0,
|
||||
pickerQuery: { pageNum: 1, pageSize: 10, keyword: undefined },
|
||||
pickerSelection: [],
|
||||
// 供应商选择器
|
||||
supplierPickerOpen: false,
|
||||
supplierLoading: false,
|
||||
supplierList: [],
|
||||
supplierTotal: 0,
|
||||
supplierQuery: { pageNum: 1, pageSize: 10, name: undefined },
|
||||
// 到货
|
||||
deliveryList: [],
|
||||
deliveryLoading: false,
|
||||
upload: { headers: { Authorization: 'Bearer ' + getToken() } },
|
||||
progressColor: '#5b8db8'
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
uploadUrl() {
|
||||
return process.env.VUE_APP_BASE_API + '/erp/purchasePlan/' + (this.current.planId || '') + '/importDelivery'
|
||||
},
|
||||
itemsWeight() {
|
||||
return (this.form.items || []).reduce((s, i) => s + (Number(i.weight) || 0), 0).toFixed(3)
|
||||
}
|
||||
},
|
||||
created() {
|
||||
this.getList()
|
||||
},
|
||||
methods: {
|
||||
getList(keepCurrent) {
|
||||
this.loading = true
|
||||
listPurchasePlan(this.queryParams).then(res => {
|
||||
this.planList = res.rows || []
|
||||
this.total = res.total || 0
|
||||
this.loading = false
|
||||
if (!keepCurrent && this.mode !== 'edit') {
|
||||
if (this.planList.length) this.selectPlan(this.planList[0])
|
||||
else { this.mode = 'empty'; this.current = {} }
|
||||
}
|
||||
})
|
||||
purchasePlanStatistics(this.queryParams).then(res => { this.stats = res.data || { total: 0, completed: 0 } })
|
||||
},
|
||||
handleQuery() {
|
||||
this.queryParams.pageNum = 1
|
||||
this.getList()
|
||||
},
|
||||
selectPlan(p) {
|
||||
this.activeTab = 'items'
|
||||
this.mode = 'view'
|
||||
this.current = { ...p }
|
||||
this.refreshDetail()
|
||||
},
|
||||
refreshDetail() {
|
||||
const planId = this.current.planId
|
||||
if (!planId) return
|
||||
getPurchasePlan(planId).then(res => { this.current = { ...this.current, ...(res.data || {}) } })
|
||||
this.deliveryLoading = true
|
||||
listDelivery(planId).then(res => { this.deliveryList = res.data || [] }).finally(() => { this.deliveryLoading = false })
|
||||
},
|
||||
// ---- 新增 / 编辑 ----
|
||||
resetForm() {
|
||||
this.form = { planId: null, planNo: '', supplier: '', purchaseDate: '', remark: '', items: [], orderIds: [], contractCodes: [] }
|
||||
this.selectedContracts = []
|
||||
this.newRowDefaults = null
|
||||
this.batchFill = { productType: '热轧卷板', material: '', grade: '', coilNo: '', width: '', thickness: '', widthTolerance: '', thicknessTolerance: '', weight: '', quantity: '', supplier: '' }
|
||||
this.batchRows = 0
|
||||
},
|
||||
handleAdd() {
|
||||
this.resetForm()
|
||||
this.mode = 'edit'
|
||||
},
|
||||
handleEdit() {
|
||||
getPurchasePlan(this.current.planId).then(res => {
|
||||
const d = res.data || {}
|
||||
this.form = {
|
||||
planId: d.planId, planNo: d.planNo, supplier: d.supplier,
|
||||
purchaseDate: d.purchaseDate, remark: d.remark,
|
||||
items: d.items || [], orderIds: d.orderIds || [], contractCodes: d.contractCodes || []
|
||||
}
|
||||
this.selectedContracts = []
|
||||
this.mode = 'edit'
|
||||
})
|
||||
},
|
||||
cancelEdit() {
|
||||
this.mode = this.planList.length ? 'view' : 'empty'
|
||||
if (this.planList.length) {
|
||||
const back = this.current.planId ? this.planList.find(p => p.planId === this.current.planId) : this.planList[0]
|
||||
this.selectPlan(back || this.planList[0])
|
||||
}
|
||||
},
|
||||
// ---- 合同选择器 ----
|
||||
openContractPicker() {
|
||||
this.pickerQuery.pageNum = 1
|
||||
this.loadPicker()
|
||||
this.pickerOpen = true
|
||||
},
|
||||
reloadPicker() {
|
||||
this.pickerQuery.pageNum = 1
|
||||
this.loadPicker()
|
||||
},
|
||||
loadPicker() {
|
||||
this.pickerLoading = true
|
||||
listContracts(this.pickerQuery).then(res => {
|
||||
this.pickerList = res.rows || []
|
||||
this.pickerTotal = res.total || 0
|
||||
this.pickerLoading = false
|
||||
// 回显已选
|
||||
this.$nextTick(() => {
|
||||
if (!this.$refs.pickerTable) return
|
||||
this.pickerList.forEach(row => {
|
||||
if (this.form.orderIds.includes(row.orderId)) {
|
||||
this.$refs.pickerTable.toggleRowSelection(row, true)
|
||||
}
|
||||
})
|
||||
})
|
||||
})
|
||||
},
|
||||
onPickerSelection(sel) {
|
||||
this.pickerSelection = sel
|
||||
},
|
||||
confirmPicker() {
|
||||
this.selectedContracts = this.pickerSelection.map(c => ({
|
||||
orderId: c.orderId, orderCode: c.orderCode, contractName: c.contractName, customer: c.customer
|
||||
}))
|
||||
this.form.orderIds = this.pickerSelection.map(c => c.orderId)
|
||||
this.form.contractCodes = []
|
||||
this.pickerOpen = false
|
||||
this.deriveItems(this.form.orderIds)
|
||||
},
|
||||
removeContract(orderId) {
|
||||
this.selectedContracts = this.selectedContracts.filter(c => c.orderId !== orderId)
|
||||
this.form.orderIds = this.form.orderIds.filter(id => id !== orderId)
|
||||
this.deriveItems(this.form.orderIds)
|
||||
},
|
||||
// ---- 供应商选择器 ----
|
||||
openSupplierPicker() {
|
||||
this.supplierQuery.pageNum = 1
|
||||
this.loadSuppliers()
|
||||
this.supplierPickerOpen = true
|
||||
},
|
||||
reloadSuppliers() {
|
||||
this.supplierQuery.pageNum = 1
|
||||
this.loadSuppliers()
|
||||
},
|
||||
loadSuppliers() {
|
||||
this.supplierLoading = true
|
||||
listSupplier(this.supplierQuery).then(res => {
|
||||
this.supplierList = res.rows || []
|
||||
this.supplierTotal = res.total || 0
|
||||
this.supplierLoading = false
|
||||
})
|
||||
},
|
||||
chooseSupplier(row) {
|
||||
// 供应商选择器服务于「批量填充」对话框
|
||||
this.batchFill.supplier = row.name
|
||||
this.supplierPickerOpen = false
|
||||
},
|
||||
deriveItems(orderIds) {
|
||||
if (!orderIds || !orderIds.length) { this.form.items = []; return }
|
||||
getItemsByOrders(orderIds).then(res => {
|
||||
this.form.items = (res.data || []).map(it => ({
|
||||
productType: it.productType || '热轧卷板',
|
||||
material: it.material || '',
|
||||
grade: it.grade || '',
|
||||
coilNo: '',
|
||||
width: it.width || '',
|
||||
thickness: it.thickness || '',
|
||||
widthTolerance: it.widthTolerance || '0',
|
||||
thicknessTolerance: it.thicknessTolerance || '0',
|
||||
weight: it.weight,
|
||||
quantity: it.quantity,
|
||||
supplier: this.form.supplier || ''
|
||||
}))
|
||||
this.$modal.msgSuccess(`已载入 ${this.form.items.length} 条明细,可继续编辑`)
|
||||
})
|
||||
},
|
||||
blankItem() {
|
||||
return { productType: '热轧卷板', material: '', grade: '', coilNo: '', width: '', thickness: '', widthTolerance: '0', thicknessTolerance: '0', weight: '', quantity: '', supplier: '' }
|
||||
},
|
||||
addItem() {
|
||||
// 优先用批量默认值,其次继承上一行,最后空行;重量每行不同故清空
|
||||
const last = this.form.items[this.form.items.length - 1]
|
||||
let row
|
||||
if (this.newRowDefaults) row = { ...this.newRowDefaults }
|
||||
else if (last) row = { ...last }
|
||||
else row = this.blankItem()
|
||||
row.weight = ''
|
||||
this.form.items.push(row)
|
||||
},
|
||||
copyItem(index) {
|
||||
this.form.items.splice(index + 1, 0, { ...this.form.items[index] })
|
||||
},
|
||||
removeItem(index) {
|
||||
this.form.items.splice(index, 1)
|
||||
},
|
||||
openBatchFill() {
|
||||
this.batchFillOpen = true
|
||||
},
|
||||
batchFillKeys() {
|
||||
const f = this.batchFill
|
||||
const keys = ['productType', 'material', 'grade', 'coilNo', 'width', 'thickness', 'widthTolerance', 'thicknessTolerance', 'weight', 'quantity', 'supplier']
|
||||
return keys.filter(k => f[k] !== '' && f[k] != null)
|
||||
},
|
||||
applyBatchFill() {
|
||||
const f = this.batchFill
|
||||
const filled = this.batchFillKeys()
|
||||
if (!filled.length) { this.$modal.msgWarning('请至少填写一个要填充的字段'); return }
|
||||
if (!this.form.items.length) { this.$modal.msgWarning('当前没有明细行,请用右侧「生成行并填充」'); return }
|
||||
this.form.items.forEach(it => { filled.forEach(k => { it[k] = f[k] }) })
|
||||
if (f.supplier) this.form.supplier = f.supplier
|
||||
this.saveNewRowDefaults(filled)
|
||||
this.batchFillOpen = false
|
||||
this.$modal.msgSuccess(`已填充 ${this.form.items.length} 行`)
|
||||
},
|
||||
generateRows() {
|
||||
const n = parseInt(this.batchRows, 10) || 0
|
||||
if (n <= 0) { this.$modal.msgWarning('请填写要生成的行数'); return }
|
||||
const f = this.batchFill
|
||||
const filled = this.batchFillKeys()
|
||||
for (let i = 0; i < n; i++) {
|
||||
const row = this.blankItem()
|
||||
filled.forEach(k => { row[k] = f[k] })
|
||||
this.form.items.push(row)
|
||||
}
|
||||
if (f.supplier) this.form.supplier = f.supplier
|
||||
this.saveNewRowDefaults(filled)
|
||||
this.batchFillOpen = false
|
||||
this.$modal.msgSuccess(`已生成 ${n} 行`)
|
||||
},
|
||||
saveNewRowDefaults(filled) {
|
||||
if (!this.batchFillNewRow) return
|
||||
const def = this.blankItem()
|
||||
filled.forEach(k => { def[k] = this.batchFill[k] })
|
||||
this.newRowDefaults = def
|
||||
},
|
||||
submitForm() {
|
||||
this.$refs['form'].validate(valid => {
|
||||
if (!valid) return
|
||||
if (!this.form.orderIds.length) { this.$modal.msgWarning('请先选择销售合同'); return }
|
||||
this.buttonLoading = true
|
||||
const api = this.form.planId ? updatePurchasePlan : addPurchasePlan
|
||||
const editedId = this.form.planId
|
||||
api(this.form).then(() => {
|
||||
this.$modal.msgSuccess('保存成功')
|
||||
this.mode = 'view'
|
||||
this.loading = true
|
||||
listPurchasePlan(this.queryParams).then(res => {
|
||||
this.planList = res.rows || []
|
||||
this.total = res.total || 0
|
||||
this.loading = false
|
||||
const target = editedId ? this.planList.find(p => p.planId === editedId) : this.planList[0]
|
||||
if (target) this.selectPlan(target)
|
||||
})
|
||||
purchasePlanStatistics(this.queryParams).then(res => { this.stats = res.data || { total: 0, completed: 0 } })
|
||||
}).finally(() => { this.buttonLoading = false })
|
||||
})
|
||||
},
|
||||
submitForAudit() {
|
||||
const tip = this.current.auditStatus === '2' ? '确认重新送审该计划?将再次进入审核' : '确认送审该计划?送审后将出现在采购审核页'
|
||||
this.$modal.confirm(tip).then(() => {
|
||||
this.submitLoading = true
|
||||
return submitPurchasePlan(this.current.planId)
|
||||
}).then(() => {
|
||||
this.$modal.msgSuccess('已送审')
|
||||
this.getList(true)
|
||||
this.refreshDetail()
|
||||
}).catch(() => {}).finally(() => { this.submitLoading = false })
|
||||
},
|
||||
handleDelete(row) {
|
||||
this.$modal.confirm('确认删除采购计划「' + row.planNo + '」?').then(() => {
|
||||
return delPurchasePlan(row.planId)
|
||||
}).then(() => {
|
||||
this.$modal.msgSuccess('删除成功')
|
||||
this.mode = 'empty'
|
||||
this.current = {}
|
||||
this.getList()
|
||||
}).catch(() => {})
|
||||
},
|
||||
// ---- 到货 ----
|
||||
handleUploadSuccess(res) {
|
||||
if (res.code === 200) {
|
||||
const data = res.data || {}
|
||||
if (data.kgConverted) {
|
||||
this.$alert(res.msg, '导入完成(含单位纠正)', { dangerouslyUseHTMLString: true, type: 'warning' })
|
||||
} else {
|
||||
this.$modal.msgSuccess(res.msg || '导入成功')
|
||||
}
|
||||
this.refreshDetail()
|
||||
this.getList(true)
|
||||
} else {
|
||||
this.$alert(res.msg || '导入失败', '到货文件校验未通过', { dangerouslyUseHTMLString: true, type: 'error' })
|
||||
}
|
||||
},
|
||||
handleUploadError() {
|
||||
this.$modal.msgError('上传失败,请检查文件后重试')
|
||||
},
|
||||
removeDelivery(row) {
|
||||
this.$modal.confirm('确定删除该到货记录吗?').then(() => {
|
||||
return delDelivery(row.deliveryId)
|
||||
}).then(() => {
|
||||
this.$modal.msgSuccess('删除成功')
|
||||
this.refreshDetail()
|
||||
this.getList(true)
|
||||
}).catch(() => {})
|
||||
},
|
||||
auditText(s) {
|
||||
return { '0': '待审核', '1': '已通过', '2': '已驳回', '3': '待送审' }[s] || '—'
|
||||
},
|
||||
itemStatusText(s) {
|
||||
return { '0': '未到货', '1': '部分到货', '2': '已到货' }[s] || '未到货'
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
$accent: #5b8db8;
|
||||
$line: #e4e7ed;
|
||||
$ink: #303133;
|
||||
$sub: #909399;
|
||||
|
||||
.pp-wb {
|
||||
height: calc(100vh - 84px);
|
||||
display: flex; flex-direction: column;
|
||||
background: #f5f6f8; padding: 12px; box-sizing: border-box;
|
||||
}
|
||||
.pp-main { flex: 1; display: flex; gap: 12px; min-height: 0; }
|
||||
|
||||
.pp-col { background: #fff; border: 1px solid $line; display: flex; flex-direction: column; min-height: 0; }
|
||||
.pp-plans { width: 300px; flex-shrink: 0; }
|
||||
.pp-detail { flex: 1; min-width: 0; overflow-y: auto; }
|
||||
|
||||
.pp-col-tool {
|
||||
padding: 10px; border-bottom: 1px solid $line;
|
||||
display: flex; gap: 8px; align-items: center;
|
||||
|
||||
// 仅对齐,不改高度(沿用全局 24px)
|
||||
::v-deep .el-input { flex: 1; }
|
||||
::v-deep .el-button { margin: 0; flex-shrink: 0; }
|
||||
}
|
||||
|
||||
// 供货商:输入框 + 选择按钮 并排,等高对齐
|
||||
.pp-inline-pick {
|
||||
display: flex; gap: 8px; align-items: center;
|
||||
::v-deep .el-input { flex: 1; }
|
||||
::v-deep .el-button { flex-shrink: 0; margin: 0; }
|
||||
}
|
||||
.pp-col-filter { padding: 8px 10px; border-bottom: 1px solid $line; }
|
||||
|
||||
.pp-list { flex: 1; overflow-y: auto; margin: 0; padding: 0; list-style: none; }
|
||||
.pp-li {
|
||||
padding: 10px 12px; border-bottom: 1px solid #f0f2f5; cursor: pointer; border-left: 3px solid transparent;
|
||||
&:hover { background: #f7f9fb; }
|
||||
&.active { background: #eef3f8; border-left-color: $accent; }
|
||||
}
|
||||
.pp-li-r1 { display: flex; justify-content: space-between; align-items: center; }
|
||||
.pp-no { font-size: 13px; font-weight: 600; color: $ink; }
|
||||
.pp-li-r2 { display: flex; justify-content: space-between; font-size: 12px; color: $sub; margin: 4px 0 6px; }
|
||||
.pp-w { color: #606266; }
|
||||
.pp-li-r3 { display: flex; justify-content: space-between; font-size: 11px; color: $sub; margin-top: 4px; }
|
||||
.pp-arch { font-style: normal; color: $accent; margin-left: 6px; }
|
||||
.pp-empty { text-align: center; color: $sub; padding: 36px 12px; font-size: 13px; }
|
||||
|
||||
.pp-badge {
|
||||
font-size: 11px; line-height: 16px; padding: 0 6px; border-radius: 2px;
|
||||
border: 1px solid #dcdfe6; color: $sub; background: #fafafa;
|
||||
&.a1 { color: $accent; border-color: #b9d2e6; background: #eef3f8; }
|
||||
&.a2 { color: #c45656; border-color: #e6c4c4; background: #fbf0f0; }
|
||||
&.a3 { color: #d6a256; border-color: #ecd4a6; background: #fdf6ec; }
|
||||
&.plan { margin-left: 6px; }
|
||||
&.p1 { color: $accent; border-color: #b9d2e6; }
|
||||
}
|
||||
|
||||
.pp-placeholder {
|
||||
height: 100%; display: flex; flex-direction: column; align-items: center; justify-content: center; color: $sub;
|
||||
i { font-size: 46px; margin-bottom: 12px; color: #d6dce1; }
|
||||
p { font-size: 13px; }
|
||||
}
|
||||
.pp-d-head {
|
||||
display: flex; justify-content: space-between; align-items: center;
|
||||
padding: 14px 18px; border-bottom: 1px solid $line;
|
||||
}
|
||||
.pp-d-title { font-size: 15px; font-weight: 600; color: $ink; margin-right: 8px; }
|
||||
.pp-meta { display: grid; grid-template-columns: repeat(3, 1fr); gap: 10px 24px; padding: 16px 18px; }
|
||||
.pp-meta-i {
|
||||
display: flex; flex-direction: column; font-size: 13px;
|
||||
label { color: $sub; font-size: 12px; margin-bottom: 3px; }
|
||||
span { color: $ink; }
|
||||
&.wide { grid-column: span 3; }
|
||||
}
|
||||
.pp-tabs { padding: 0 18px 18px; }
|
||||
|
||||
.pp-edit { padding: 0 0 18px; }
|
||||
.pp-form { padding: 0 18px; }
|
||||
.pp-section {
|
||||
font-size: 13px; font-weight: 600; color: $ink;
|
||||
border-left: 3px solid $accent; padding-left: 8px; margin: 16px 0 12px;
|
||||
.pp-section-act { margin-left: 10px; }
|
||||
.pp-section-hint { float: right; font-weight: 400; color: $sub; font-size: 12px; }
|
||||
}
|
||||
|
||||
/* 已选合同 chips */
|
||||
.pp-picked { display: flex; flex-wrap: wrap; gap: 8px; margin-bottom: 4px; min-height: 24px; }
|
||||
.pp-chip {
|
||||
display: inline-flex; align-items: center; gap: 6px;
|
||||
border: 1px solid #b9d2e6; background: #eef3f8; color: $accent;
|
||||
border-radius: 3px; padding: 3px 8px; font-size: 12px;
|
||||
b { font-weight: 600; }
|
||||
.pp-chip-sub { color: $sub; font-weight: 400; max-width: 220px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
|
||||
.el-icon-close { cursor: pointer; color: $sub; &:hover { color: #c45656; } }
|
||||
&.readonly { color: #606266; border-color: #dcdfe6; background: #fafafa; }
|
||||
}
|
||||
.pp-chip-tip { color: $sub; font-size: 12px; align-self: center; }
|
||||
.pp-picked-empty { color: $sub; font-size: 13px; }
|
||||
|
||||
.pp-deliv-bar { display: flex; align-items: center; gap: 12px; margin-bottom: 12px; min-height: 32px; }
|
||||
.pp-deliv-tip { color: $sub; font-size: 13px; }
|
||||
.pp-deliv-hint { color: $sub; font-size: 12px; }
|
||||
.pp-del { color: #c45656; cursor: pointer; }
|
||||
.pp-copy { color: #5b8db8; cursor: pointer; margin-right: 10px; }
|
||||
.pp-batch-tip { font-size: 12px; color: #909399; margin: 0 0 14px; line-height: 1.6; b { color: #5b8db8; } }
|
||||
.pp-batch-footer { display: flex; align-items: center; gap: 10px;
|
||||
.el-checkbox { margin-right: auto; }
|
||||
.pp-batch-gen { font-size: 13px; color: #606266; }
|
||||
}
|
||||
|
||||
/* 审核记录 */
|
||||
.pp-audit { margin: 0 18px 14px; border: 1px solid $line; border-radius: 3px; }
|
||||
.pp-audit-head { font-size: 13px; font-weight: 600; color: $ink; padding: 8px 12px; border-bottom: 1px solid $line; background: #fafbfc; }
|
||||
.pp-audit-list { margin: 0; padding: 0; list-style: none;
|
||||
li { display: flex; align-items: center; gap: 10px; padding: 8px 12px; font-size: 12px; color: #606266; border-bottom: 1px solid #f0f2f5;
|
||||
&:last-child { border-bottom: none; }
|
||||
}
|
||||
}
|
||||
.pp-audit-by { color: $ink; }
|
||||
.pp-audit-time { color: $sub; }
|
||||
.pp-audit-op { flex: 1; color: #606266;
|
||||
&.single { padding: 10px 12px; }
|
||||
}
|
||||
|
||||
.pp-istat {
|
||||
font-size: 11px; line-height: 16px; padding: 0 6px; border-radius: 2px; border: 1px solid #dcdfe6; color: $sub;
|
||||
&.s1 { color: #d6a256; border-color: #ecd4a6; background: #fdf6ec; }
|
||||
&.s2 { color: $accent; border-color: #b9d2e6; background: #eef3f8; }
|
||||
}
|
||||
|
||||
/* 合同选择器 */
|
||||
.pp-picker-tool { display: flex; gap: 8px; margin-bottom: 10px; }
|
||||
.pp-picker-count { float: left; color: $sub; font-size: 13px; line-height: 32px; }
|
||||
.pp-cnt-zero { color: #c0c4cc; }
|
||||
</style>
|
||||
Reference in New Issue
Block a user