6 changed files with 1293 additions and 6 deletions
-
7src/api/yieldReport/com_material_loss.js
-
7src/api/yieldReport/com_material_roll_up.js
-
4src/views/modules/qc/OQCResultEntry.vue
-
616src/views/modules/yieldReport/com_material_loss.vue
-
616src/views/modules/yieldReport/com_material_roll_up.vue
-
49src/views/modules/yieldReport/com_produce_report_normal.vue
@ -0,0 +1,7 @@ |
|||||
|
import { createAPI } from '@/utils/httpRequest.js' |
||||
|
|
||||
|
/** |
||||
|
* 材料损耗(调用 MaterialProcessLoss 存储过程) |
||||
|
*/ |
||||
|
export const materialProcessLoss = data => createAPI(`/pms/yieldReportCommons/materialProcessLoss`, 'post', data) |
||||
|
|
||||
@ -0,0 +1,7 @@ |
|||||
|
import { createAPI } from '@/utils/httpRequest.js' |
||||
|
|
||||
|
/** |
||||
|
* 材料接卷(调用 MaterialProcessRollUp 存储过程) |
||||
|
*/ |
||||
|
export const materialProcessRollUp = data => createAPI(`/pms/yieldReportCommons/materialProcessRollUp`, 'post', data) |
||||
|
|
||||
@ -0,0 +1,616 @@ |
|||||
|
<template> |
||||
|
<div class="customer-css"> |
||||
|
<el-dialog :title="titleCon" v-drag v-bind="$attrs" v-on="$listeners" |
||||
|
width="600px" class="material-dialog"> |
||||
|
<div class="material-content"> |
||||
|
<el-form :model="pageData" label-position="top" label-width="100px"> |
||||
|
<!-- 材料信息卡片 --> |
||||
|
<div class="material-info-card"> |
||||
|
<div class="info-header"> |
||||
|
<i class="el-icon-document"></i> |
||||
|
<span>材料信息</span> |
||||
|
</div> |
||||
|
<div class="info-content"> |
||||
|
<el-row :gutter="15"> |
||||
|
<el-col :span="12"> |
||||
|
<div class="info-row"> |
||||
|
<label class="info-label">材料卷号:</label> |
||||
|
<span class="info-value">{{ pageData.rmRollNo || '-' }}</span> |
||||
|
</div> |
||||
|
</el-col> |
||||
|
<el-col :span="12"> |
||||
|
<div class="info-row"> |
||||
|
<label class="info-label">零部件编码:</label> |
||||
|
<span class="info-value">{{ pageData.partNo || '-' }}</span> |
||||
|
</div> |
||||
|
</el-col> |
||||
|
</el-row> |
||||
|
<el-row :gutter="15"> |
||||
|
<el-col :span="24"> |
||||
|
<div class="info-row"> |
||||
|
<label class="info-label">零部件名称:</label> |
||||
|
<span class="info-value">{{ pageData.partDesc || '-' }}</span> |
||||
|
</div> |
||||
|
</el-col> |
||||
|
</el-row> |
||||
|
<el-row :gutter="15"> |
||||
|
<el-col :span="12"> |
||||
|
<div class="info-row"> |
||||
|
<label class="info-label">规格型号:</label> |
||||
|
<span class="info-value">{{ pageData.spec || '-' }}</span> |
||||
|
</div> |
||||
|
</el-col> |
||||
|
</el-row> |
||||
|
</div> |
||||
|
</div> |
||||
|
|
||||
|
<!-- 损耗设置区域 --> |
||||
|
<div class="return-settings"> |
||||
|
<el-row :gutter="15"> |
||||
|
<el-col :span="8"> |
||||
|
<el-form-item label="上机数量" class="form-item-enhanced"> |
||||
|
<el-input |
||||
|
v-model="displayOnMachineQty" |
||||
|
disabled |
||||
|
size="large" |
||||
|
style="width: 100%"> |
||||
|
</el-input> |
||||
|
</el-form-item> |
||||
|
</el-col> |
||||
|
<el-col :span="8"> |
||||
|
<el-form-item label="暂存数量" class="form-item-enhanced"> |
||||
|
<el-input class="inlineNumber numInput" |
||||
|
v-model="pageData.returnQty" |
||||
|
type="number" |
||||
|
placeholder="请输入暂存数量" |
||||
|
size="large" |
||||
|
@input="calculateRemainQty" |
||||
|
style="width: 100%"> |
||||
|
</el-input> |
||||
|
</el-form-item> |
||||
|
</el-col> |
||||
|
<el-col :span="8"> |
||||
|
<el-form-item label="剩余数量" class="form-item-enhanced"> |
||||
|
<el-input |
||||
|
v-model="displayRemainQty" |
||||
|
disabled |
||||
|
size="large" |
||||
|
:class="{'remain-negative': pageData.remainQty < 0}" |
||||
|
style="width: 100%"> |
||||
|
</el-input> |
||||
|
</el-form-item> |
||||
|
</el-col> |
||||
|
</el-row> |
||||
|
|
||||
|
<!-- 备注 --> |
||||
|
<el-row style="margin-bottom: 30px"> |
||||
|
<el-col :span="24"> |
||||
|
<el-form-item label="备注" > |
||||
|
<el-input |
||||
|
v-model="pageData.remark" |
||||
|
type="textarea" |
||||
|
:rows="3" |
||||
|
placeholder="请输入备注" |
||||
|
show-word-limit> |
||||
|
</el-input> |
||||
|
</el-form-item> |
||||
|
</el-col> |
||||
|
</el-row> |
||||
|
</div> |
||||
|
</el-form> |
||||
|
</div> |
||||
|
|
||||
|
<span slot="footer" class="dialog-footer"> |
||||
|
<button class="action-btn secondary" @click="submitMaterialLoss"> |
||||
|
{{ buttons.confirmButton }} |
||||
|
</button> |
||||
|
<button class="action-btn secondary" @click="closeDialog"> |
||||
|
{{ buttons.closeButton }} |
||||
|
</button> |
||||
|
</span> |
||||
|
</el-dialog> |
||||
|
</div> |
||||
|
</template> |
||||
|
|
||||
|
<script> |
||||
|
import { |
||||
|
materialProcessLoss |
||||
|
} from '@/api/yieldReport/com_material_loss.js'; |
||||
|
import getLodop from '@/utils/LodopFuncs.js'; // 打印控件 |
||||
|
import labelPrintTemplates from '@/mixins/labelPrintTemplates.js'; // 打印模板mixin |
||||
|
|
||||
|
var functionId = 'C10000019'; |
||||
|
|
||||
|
export default { |
||||
|
mixins: [labelPrintTemplates], // 添加打印模板mixin |
||||
|
data() { |
||||
|
return { |
||||
|
titleCon: '材料暂存', |
||||
|
scheduleData: { |
||||
|
site: this.$store.state.user.site, |
||||
|
username: this.$store.state.user.name, |
||||
|
seqNo: '', |
||||
|
orderNo: '', |
||||
|
itemNo: 0, |
||||
|
}, |
||||
|
pageData: { |
||||
|
site: this.$store.state.user.site, |
||||
|
orderNo: '', |
||||
|
itemNo: '', |
||||
|
seqNo: '', |
||||
|
rollNo: '', |
||||
|
rmRollNo: '', |
||||
|
partNo: '', |
||||
|
partDesc: '', |
||||
|
spec: '', |
||||
|
onMachineQty: 0, // 上机数量(来自行数据的数量) |
||||
|
returnQty: 0, // 损耗数量 |
||||
|
remainQty: 0, // 剩余数量 |
||||
|
remark: '', // 备注 |
||||
|
histSeqNo: '', |
||||
|
operatorId: '', |
||||
|
}, |
||||
|
operatorData: { |
||||
|
site: this.$store.state.user.site, |
||||
|
username: this.$store.state.user.name, |
||||
|
operatorId: '', |
||||
|
operatorName: '', |
||||
|
}, |
||||
|
buttons: { |
||||
|
confirmButton: '确定', |
||||
|
closeButton: '关闭', |
||||
|
}, |
||||
|
} |
||||
|
}, |
||||
|
computed: { |
||||
|
// 显示上机数量(如果为0或空则显示空字符串) |
||||
|
displayOnMachineQty() { |
||||
|
return this.pageData.onMachineQty || this.pageData.onMachineQty === 0 ? String(this.pageData.onMachineQty) : ''; |
||||
|
}, |
||||
|
// 显示剩余数量(如果为0或空则显示空字符串) |
||||
|
displayRemainQty() { |
||||
|
return this.pageData.remainQty || this.pageData.remainQty === 0 ? String(this.pageData.remainQty) : ''; |
||||
|
} |
||||
|
}, |
||||
|
methods: { |
||||
|
//初始化组件的参数 |
||||
|
init(scheduleData, operatorData, materialRow) { |
||||
|
//初始化参数 |
||||
|
this.scheduleData = scheduleData; |
||||
|
this.operatorData = JSON.parse(JSON.stringify(operatorData)); |
||||
|
|
||||
|
//设置材料信息 |
||||
|
this.pageData.orderNo = scheduleData.orderNo; |
||||
|
this.pageData.itemNo = scheduleData.itemNo; |
||||
|
this.pageData.seqNo = scheduleData.seqNo; |
||||
|
this.pageData.rollNo = scheduleData.rollNo; |
||||
|
this.pageData.operatorId = operatorData.operatorId; |
||||
|
|
||||
|
// 从行数据获取材料信息 |
||||
|
this.pageData.rmRollNo = materialRow.rmRollNo || ''; |
||||
|
this.pageData.partNo = materialRow.partNo || ''; |
||||
|
this.pageData.partDesc = materialRow.partDesc || ''; |
||||
|
this.pageData.spec = materialRow.spec || ''; |
||||
|
this.pageData.histSeqNo = materialRow.histSeqNo || ''; |
||||
|
|
||||
|
// 获取上机数量(从行数据的 transQty 字段) |
||||
|
const transQty = parseFloat(materialRow.transQty); |
||||
|
this.pageData.onMachineQty = isNaN(transQty) ? 0 : transQty; |
||||
|
// 重置损耗数量、剩余数量和备注 |
||||
|
this.pageData.returnQty = 0; |
||||
|
this.pageData.remainQty = this.pageData.onMachineQty; |
||||
|
this.pageData.remark = ''; |
||||
|
|
||||
|
this.titleCon = '材料暂存'; |
||||
|
}, |
||||
|
|
||||
|
/*关闭modal*/ |
||||
|
closeDialog(){ |
||||
|
//刷新报工的页面 |
||||
|
this.$emit('refreshPageData'); |
||||
|
//关闭当前的页面 |
||||
|
this.$emit('update:visible', false); |
||||
|
}, |
||||
|
|
||||
|
/*计算剩余数量*/ |
||||
|
calculateRemainQty() { |
||||
|
const onMachineQty = parseFloat(this.pageData.onMachineQty) || 0; |
||||
|
const returnQty = parseFloat(this.pageData.returnQty) || 0; |
||||
|
this.pageData.remainQty = onMachineQty - returnQty; |
||||
|
}, |
||||
|
|
||||
|
/*提交损耗*/ |
||||
|
submitMaterialLoss() { |
||||
|
// 如果没有填写损耗数量,默认为0 |
||||
|
if (!this.pageData.returnQty || this.pageData.returnQty === '' || this.pageData.returnQty < 0) { |
||||
|
this.pageData.returnQty = 0; |
||||
|
} |
||||
|
|
||||
|
// 计算剩余数量 |
||||
|
this.calculateRemainQty(); |
||||
|
|
||||
|
// 验证剩余数量必须大于等于0 |
||||
|
if (this.pageData.remainQty < 0) { |
||||
|
this.$message.warning('暂存数量不能大于上机数量!'); |
||||
|
return false; |
||||
|
} |
||||
|
|
||||
|
// 构建提交数据(只传损耗数量和备注,不传上机数量和剩余数量) |
||||
|
const submitData = { |
||||
|
site: this.pageData.site, |
||||
|
orderNo: this.pageData.orderNo, |
||||
|
itemNo: this.pageData.itemNo, |
||||
|
seqNo: this.pageData.seqNo, |
||||
|
rollNo: this.pageData.rmRollNo, |
||||
|
returnQty: this.pageData.returnQty, |
||||
|
histSeqNo: this.pageData.histSeqNo, |
||||
|
operatorId: this.pageData.operatorId, |
||||
|
remark: this.pageData.remark || '' // 备注(可选,默认为空字符串) |
||||
|
}; |
||||
|
|
||||
|
// 调用后端API(调用 MaterialProcessLoss 存储过程) |
||||
|
materialProcessLoss(submitData).then(({data}) => { |
||||
|
//判断是否存在异常 |
||||
|
if(data.code == 500 || data.code == 400){ |
||||
|
this.$message.error(data.msg || data.message); |
||||
|
} else if (data.code == 201) { |
||||
|
// code=201 表示需要打印标签 |
||||
|
this.$message.success(data.msg || '操作成功'); |
||||
|
|
||||
|
// 获取打印参数并打印(存储过程返回的打印参数在printData中) |
||||
|
if (data.printData) { |
||||
|
// 将单个打印数据对象包装成数组 |
||||
|
const printDataList = [data.printData]; |
||||
|
this.executePrint(printDataList); |
||||
|
} else { |
||||
|
console.warn('未获取到打印参数'); |
||||
|
} |
||||
|
|
||||
|
//关闭当前的页面 |
||||
|
this.closeDialog(); |
||||
|
} else { |
||||
|
//先提示 后关闭 |
||||
|
this.$message.success(data.msg || data.message || '操作成功'); |
||||
|
//关闭当前的页面 |
||||
|
this.closeDialog(); |
||||
|
} |
||||
|
}).catch((error) => { |
||||
|
this.$message.error('操作失败:' + (error.message || '未知错误')); |
||||
|
}); |
||||
|
}, |
||||
|
|
||||
|
/** |
||||
|
* 执行打印(直接使用存储过程返回的打印参数) |
||||
|
* @param {Array} printDataList - 存储过程返回的打印数据列表 |
||||
|
*/ |
||||
|
executePrint(printDataList) { |
||||
|
try { |
||||
|
// 1. 获取 LODOP 打印控件 |
||||
|
const LODOP = getLodop(); |
||||
|
if (!LODOP) { |
||||
|
this.$message.warning('无法连接到打印控件,跳过打印'); |
||||
|
return; |
||||
|
} |
||||
|
|
||||
|
// 2. 获取默认打印机 |
||||
|
const printerCount = LODOP.GET_PRINTER_COUNT(); |
||||
|
if (printerCount === 0) { |
||||
|
this.$message.warning('未检测到打印机,跳过打印'); |
||||
|
return; |
||||
|
} |
||||
|
const defaultPrinterName = LODOP.GET_PRINTER_NAME(0); |
||||
|
|
||||
|
// 3. 检查打印数据中的labelNo(标签模板编号) |
||||
|
if (!printDataList || printDataList.length === 0) { |
||||
|
console.warn('打印数据为空'); |
||||
|
return; |
||||
|
} |
||||
|
|
||||
|
// 获取第一条数据的labelNo |
||||
|
const labelNo = printDataList[0].labelNo; |
||||
|
if (!labelNo) { |
||||
|
console.warn('未找到标签模板编号'); |
||||
|
return; |
||||
|
} |
||||
|
|
||||
|
// 4. 执行模板打印 |
||||
|
this.executePrintWithTemplate(LODOP, printDataList, labelNo, defaultPrinterName); |
||||
|
|
||||
|
this.$message.success('标签打印任务已发送!'); |
||||
|
|
||||
|
} catch (error) { |
||||
|
console.error('打印失败:', error); |
||||
|
this.$message.warning('打印失败: ' + error.message); |
||||
|
} |
||||
|
}, |
||||
|
|
||||
|
/** |
||||
|
* 执行模板打印 |
||||
|
* @param {Object} LODOP - 打印控件对象 |
||||
|
* @param {Array} printDataList - 打印数据列表 |
||||
|
* @param {String} labelNo - 标签模板编号 (A001/A002/A003) |
||||
|
* @param {String} printerName - 打印机名称 |
||||
|
*/ |
||||
|
executePrintWithTemplate(LODOP, printDataList, labelNo, printerName) { |
||||
|
LODOP.PRINT_INIT('材料暂存标签打印'); |
||||
|
|
||||
|
// 设置打印模式,隐藏水印 |
||||
|
LODOP.SET_PRINT_MODE("PRINT_NOCOLLATE", true); |
||||
|
|
||||
|
// 设置打印机 |
||||
|
LODOP.SET_PRINTER_INDEX(printerName); |
||||
|
|
||||
|
// 循环打印每个标签 |
||||
|
for (let i = 0; i < printDataList.length; i++) { |
||||
|
const printData = printDataList[i]; |
||||
|
const isNewPage = i > 0; |
||||
|
// 根据 labelNo 调用不同的打印方法(来自 labelPrintTemplates mixin) |
||||
|
if (labelNo === 'A001') { |
||||
|
this.printLabelA001(LODOP, printData, isNewPage); |
||||
|
} else if (labelNo === 'A002') { |
||||
|
this.printLabelA002(LODOP, printData, isNewPage); |
||||
|
} else if (labelNo === 'A003') { |
||||
|
this.printLabelA003(LODOP, printData, isNewPage); |
||||
|
} else { |
||||
|
console.warn(`未知的标签模板:${labelNo}`); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
// 预览打印(避免水印) |
||||
|
LODOP.PREVIEW(); |
||||
|
}, |
||||
|
}, |
||||
|
} |
||||
|
</script> |
||||
|
|
||||
|
<style scoped lang="scss"> |
||||
|
.numInput /deep/ .el-input__inner{ |
||||
|
text-align: right; |
||||
|
} |
||||
|
/deep/ .inlineNumber input::-webkit-outer-spin-button, |
||||
|
/deep/ .inlineNumber input::-webkit-inner-spin-button { |
||||
|
-webkit-appearance: none; |
||||
|
|
||||
|
} |
||||
|
/deep/ .inlineNumber input[type="number"]{ |
||||
|
-moz-appearance: textfield; |
||||
|
padding-right: 5px !important; |
||||
|
} |
||||
|
|
||||
|
// 材料暂存对话框样式 |
||||
|
.material-dialog { |
||||
|
::v-deep .el-dialog { |
||||
|
border-radius: 8px; |
||||
|
overflow: hidden; |
||||
|
|
||||
|
.el-dialog__header { |
||||
|
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); |
||||
|
padding: 18px 20px; |
||||
|
|
||||
|
.el-dialog__title { |
||||
|
color: #fff; |
||||
|
font-size: 16px; |
||||
|
font-weight: 600; |
||||
|
} |
||||
|
|
||||
|
.el-dialog__headerbtn { |
||||
|
.el-dialog__close { |
||||
|
color: #fff; |
||||
|
font-size: 18px; |
||||
|
|
||||
|
&:hover { |
||||
|
color: #f0f0f0; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
.el-dialog__body { |
||||
|
padding: 25px; |
||||
|
background-color: #f8f9fa; |
||||
|
} |
||||
|
|
||||
|
.el-dialog__footer { |
||||
|
padding: 15px 20px; |
||||
|
background-color: #fff; |
||||
|
border-top: 1px solid #e9ecef; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
.material-content { |
||||
|
.form-item-enhanced { |
||||
|
margin-bottom: 10px; |
||||
|
|
||||
|
::v-deep .el-form-item__label { |
||||
|
color: #495057; |
||||
|
font-weight: 500; |
||||
|
font-size: 14px; |
||||
|
margin-bottom: 8px; |
||||
|
} |
||||
|
|
||||
|
::v-deep .el-input { |
||||
|
.el-input__inner { |
||||
|
border-radius: 6px; |
||||
|
border: 1px solid #dee2e6; |
||||
|
transition: all 0.3s; |
||||
|
height: 42px; |
||||
|
line-height: 42px; |
||||
|
font-size: 15px; |
||||
|
|
||||
|
&:focus { |
||||
|
border-color: #667eea; |
||||
|
box-shadow: 0 0 0 3px rgba(102, 126, 234, 0.1); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
// 文本域样式 |
||||
|
::v-deep .el-textarea { |
||||
|
.el-textarea__inner { |
||||
|
border-radius: 6px; |
||||
|
border: 1px solid #dee2e6; |
||||
|
transition: all 0.3s; |
||||
|
font-size: 14px; |
||||
|
padding: 8px 12px; |
||||
|
line-height: 1.5; |
||||
|
|
||||
|
&:focus { |
||||
|
border-color: #667eea; |
||||
|
box-shadow: 0 0 0 3px rgba(102, 126, 234, 0.1); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
// 剩余数量为负数时的红色警告样式 |
||||
|
::v-deep .remain-negative { |
||||
|
.el-input__inner { |
||||
|
color: #f56c6c; |
||||
|
font-weight: 600; |
||||
|
border-color: #f56c6c; |
||||
|
background-color: #fef0f0; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
// 物料信息卡片样式 - 白色框连起来 |
||||
|
.material-info-card { |
||||
|
background: linear-gradient(135deg, #667eea15 0%, #764ba215 100%); |
||||
|
border-radius: 8px; |
||||
|
padding: 16px; |
||||
|
margin-bottom: 20px; |
||||
|
border: 1px solid #e3e8f0; |
||||
|
box-shadow: 0 2px 8px rgba(102, 126, 234, 0.08); |
||||
|
animation: fadeInDown 0.5s ease-out; |
||||
|
|
||||
|
.info-header { |
||||
|
display: flex; |
||||
|
align-items: center; |
||||
|
margin-bottom: 12px; |
||||
|
padding-bottom: 10px; |
||||
|
border-bottom: 1px solid #dee2e6; |
||||
|
|
||||
|
i { |
||||
|
font-size: 18px; |
||||
|
color: #667eea; |
||||
|
margin-right: 8px; |
||||
|
} |
||||
|
|
||||
|
span { |
||||
|
font-size: 14px; |
||||
|
font-weight: 600; |
||||
|
color: #495057; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
.info-content { |
||||
|
background-color: rgba(255, 255, 255, 0.8); |
||||
|
border-radius: 4px; |
||||
|
padding: 12px; |
||||
|
|
||||
|
.info-row { |
||||
|
display: flex; |
||||
|
align-items: center; |
||||
|
padding: 4px 0; |
||||
|
|
||||
|
&:not(:last-child) { |
||||
|
border-bottom: 1px dashed #e9ecef; |
||||
|
} |
||||
|
|
||||
|
.info-label { |
||||
|
font-size: 13px; |
||||
|
color: #6c757d; |
||||
|
min-width: 90px; |
||||
|
font-weight: 500; |
||||
|
} |
||||
|
|
||||
|
.info-value { |
||||
|
font-size: 13px; |
||||
|
color: #212529; |
||||
|
font-weight: 600; |
||||
|
flex: 1; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
// 暂存设置区域 |
||||
|
.return-settings { |
||||
|
background: #fff; |
||||
|
border-radius: 8px; |
||||
|
padding: 16px; |
||||
|
border: 1px solid #e3e8f0; |
||||
|
box-shadow: 0 2px 8px rgba(102, 126, 234, 0.05); |
||||
|
} |
||||
|
|
||||
|
// 底部按钮样式 |
||||
|
.dialog-footer { |
||||
|
display: flex; |
||||
|
justify-content: center; |
||||
|
gap: 12px; |
||||
|
padding: 0; |
||||
|
|
||||
|
.action-btn { |
||||
|
min-width: 80px; |
||||
|
padding: 6px 16px; |
||||
|
border-radius: 16px; |
||||
|
font-size: 13px; |
||||
|
font-weight: 500; |
||||
|
cursor: pointer; |
||||
|
transition: all 0.2s ease; |
||||
|
display: inline-flex; |
||||
|
align-items: center; |
||||
|
justify-content: center; |
||||
|
gap: 4px; |
||||
|
|
||||
|
i { |
||||
|
font-size: 13px; |
||||
|
} |
||||
|
|
||||
|
&.primary { |
||||
|
background: #17B3A3; |
||||
|
border: none; |
||||
|
color: white; |
||||
|
|
||||
|
&:hover { |
||||
|
background: #13998b; |
||||
|
box-shadow: 0 4px 12px rgba(23, 179, 163, 0.4); |
||||
|
transform: translateY(-1px); |
||||
|
} |
||||
|
|
||||
|
&:active { |
||||
|
transform: translateY(0); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
&.secondary { |
||||
|
background: white; |
||||
|
border: 1px solid #17B3A3; |
||||
|
color: #17B3A3; |
||||
|
|
||||
|
&:hover { |
||||
|
background: #17B3A3; |
||||
|
color: white; |
||||
|
} |
||||
|
|
||||
|
&:active { |
||||
|
transform: scale(0.98); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
// 动画效果 |
||||
|
@keyframes fadeInDown { |
||||
|
from { |
||||
|
opacity: 0; |
||||
|
transform: translateY(-10px); |
||||
|
} |
||||
|
to { |
||||
|
opacity: 1; |
||||
|
transform: translateY(0); |
||||
|
} |
||||
|
} |
||||
|
</style> |
||||
|
|
||||
@ -0,0 +1,616 @@ |
|||||
|
<template> |
||||
|
<div class="customer-css"> |
||||
|
<el-dialog :title="titleCon" v-drag v-bind="$attrs" v-on="$listeners" |
||||
|
width="600px" class="material-dialog"> |
||||
|
<div class="material-content"> |
||||
|
<el-form :model="pageData" label-position="top" label-width="100px"> |
||||
|
<!-- 材料信息卡片 --> |
||||
|
<div class="material-info-card"> |
||||
|
<div class="info-header"> |
||||
|
<i class="el-icon-document"></i> |
||||
|
<span>材料信息</span> |
||||
|
</div> |
||||
|
<div class="info-content"> |
||||
|
<el-row :gutter="15"> |
||||
|
<el-col :span="12"> |
||||
|
<div class="info-row"> |
||||
|
<label class="info-label">材料卷号:</label> |
||||
|
<span class="info-value">{{ pageData.rmRollNo || '-' }}</span> |
||||
|
</div> |
||||
|
</el-col> |
||||
|
<el-col :span="12"> |
||||
|
<div class="info-row"> |
||||
|
<label class="info-label">零部件编码:</label> |
||||
|
<span class="info-value">{{ pageData.partNo || '-' }}</span> |
||||
|
</div> |
||||
|
</el-col> |
||||
|
</el-row> |
||||
|
<el-row :gutter="15"> |
||||
|
<el-col :span="24"> |
||||
|
<div class="info-row"> |
||||
|
<label class="info-label">零部件名称:</label> |
||||
|
<span class="info-value">{{ pageData.partDesc || '-' }}</span> |
||||
|
</div> |
||||
|
</el-col> |
||||
|
</el-row> |
||||
|
<el-row :gutter="15"> |
||||
|
<el-col :span="12"> |
||||
|
<div class="info-row"> |
||||
|
<label class="info-label">规格型号:</label> |
||||
|
<span class="info-value">{{ pageData.spec || '-' }}</span> |
||||
|
</div> |
||||
|
</el-col> |
||||
|
</el-row> |
||||
|
</div> |
||||
|
</div> |
||||
|
|
||||
|
<!-- 接卷设置区域 --> |
||||
|
<div class="return-settings"> |
||||
|
<el-row :gutter="15"> |
||||
|
<el-col :span="8"> |
||||
|
<el-form-item label="上机数量" class="form-item-enhanced"> |
||||
|
<el-input |
||||
|
v-model="displayOnMachineQty" |
||||
|
disabled |
||||
|
size="large" |
||||
|
style="width: 100%"> |
||||
|
</el-input> |
||||
|
</el-form-item> |
||||
|
</el-col> |
||||
|
<el-col :span="8"> |
||||
|
<el-form-item label="拼卷数量" class="form-item-enhanced"> |
||||
|
<el-input class="inlineNumber numInput" |
||||
|
v-model="pageData.returnQty" |
||||
|
type="number" |
||||
|
placeholder="请输入拼卷数量" |
||||
|
size="large" |
||||
|
@input="calculateRemainQty" |
||||
|
style="width: 100%"> |
||||
|
</el-input> |
||||
|
</el-form-item> |
||||
|
</el-col> |
||||
|
<el-col :span="8"> |
||||
|
<el-form-item label="剩余数量" class="form-item-enhanced"> |
||||
|
<el-input |
||||
|
v-model="displayRemainQty" |
||||
|
disabled |
||||
|
size="large" |
||||
|
:class="{'remain-negative': pageData.remainQty < 0}" |
||||
|
style="width: 100%"> |
||||
|
</el-input> |
||||
|
</el-form-item> |
||||
|
</el-col> |
||||
|
</el-row> |
||||
|
|
||||
|
<!-- 备注 --> |
||||
|
<el-row style="margin-bottom: 30px"> |
||||
|
<el-col :span="24"> |
||||
|
<el-form-item label="备注" > |
||||
|
<el-input |
||||
|
v-model="pageData.remark" |
||||
|
type="textarea" |
||||
|
:rows="3" |
||||
|
placeholder="请输入备注" |
||||
|
show-word-limit> |
||||
|
</el-input> |
||||
|
</el-form-item> |
||||
|
</el-col> |
||||
|
</el-row> |
||||
|
</div> |
||||
|
</el-form> |
||||
|
</div> |
||||
|
|
||||
|
<span slot="footer" class="dialog-footer"> |
||||
|
<button class="action-btn secondary" @click="submitMaterialRollUp"> |
||||
|
{{ buttons.confirmButton }} |
||||
|
</button> |
||||
|
<button class="action-btn secondary" @click="closeDialog"> |
||||
|
{{ buttons.closeButton }} |
||||
|
</button> |
||||
|
</span> |
||||
|
</el-dialog> |
||||
|
</div> |
||||
|
</template> |
||||
|
|
||||
|
<script> |
||||
|
import { |
||||
|
materialProcessRollUp |
||||
|
} from '@/api/yieldReport/com_material_roll_up.js'; |
||||
|
import getLodop from '@/utils/LodopFuncs.js'; // 打印控件 |
||||
|
import labelPrintTemplates from '@/mixins/labelPrintTemplates.js'; // 打印模板mixin |
||||
|
|
||||
|
var functionId = 'C10000019'; |
||||
|
|
||||
|
export default { |
||||
|
mixins: [labelPrintTemplates], // 添加打印模板mixin |
||||
|
data() { |
||||
|
return { |
||||
|
titleCon: '材料拼卷', |
||||
|
scheduleData: { |
||||
|
site: this.$store.state.user.site, |
||||
|
username: this.$store.state.user.name, |
||||
|
seqNo: '', |
||||
|
orderNo: '', |
||||
|
itemNo: 0, |
||||
|
}, |
||||
|
pageData: { |
||||
|
site: this.$store.state.user.site, |
||||
|
orderNo: '', |
||||
|
itemNo: '', |
||||
|
seqNo: '', |
||||
|
rollNo: '', |
||||
|
rmRollNo: '', |
||||
|
partNo: '', |
||||
|
partDesc: '', |
||||
|
spec: '', |
||||
|
onMachineQty: 0, // 上机数量(来自行数据的数量) |
||||
|
returnQty: 0, // 接卷数量 |
||||
|
remainQty: 0, // 剩余数量 |
||||
|
remark: '', // 备注 |
||||
|
histSeqNo: '', |
||||
|
operatorId: '', |
||||
|
}, |
||||
|
operatorData: { |
||||
|
site: this.$store.state.user.site, |
||||
|
username: this.$store.state.user.name, |
||||
|
operatorId: '', |
||||
|
operatorName: '', |
||||
|
}, |
||||
|
buttons: { |
||||
|
confirmButton: '确定', |
||||
|
closeButton: '关闭', |
||||
|
}, |
||||
|
} |
||||
|
}, |
||||
|
computed: { |
||||
|
// 显示上机数量(如果为0或空则显示空字符串) |
||||
|
displayOnMachineQty() { |
||||
|
return this.pageData.onMachineQty || this.pageData.onMachineQty === 0 ? String(this.pageData.onMachineQty) : ''; |
||||
|
}, |
||||
|
// 显示剩余数量(如果为0或空则显示空字符串) |
||||
|
displayRemainQty() { |
||||
|
return this.pageData.remainQty || this.pageData.remainQty === 0 ? String(this.pageData.remainQty) : ''; |
||||
|
} |
||||
|
}, |
||||
|
methods: { |
||||
|
//初始化组件的参数 |
||||
|
init(scheduleData, operatorData, materialRow) { |
||||
|
//初始化参数 |
||||
|
this.scheduleData = scheduleData; |
||||
|
this.operatorData = JSON.parse(JSON.stringify(operatorData)); |
||||
|
|
||||
|
//设置材料信息 |
||||
|
this.pageData.orderNo = scheduleData.orderNo; |
||||
|
this.pageData.itemNo = scheduleData.itemNo; |
||||
|
this.pageData.seqNo = scheduleData.seqNo; |
||||
|
this.pageData.rollNo = scheduleData.rollNo; |
||||
|
this.pageData.operatorId = operatorData.operatorId; |
||||
|
|
||||
|
// 从行数据获取材料信息 |
||||
|
this.pageData.rmRollNo = materialRow.rmRollNo || ''; |
||||
|
this.pageData.partNo = materialRow.partNo || ''; |
||||
|
this.pageData.partDesc = materialRow.partDesc || ''; |
||||
|
this.pageData.spec = materialRow.spec || ''; |
||||
|
this.pageData.histSeqNo = materialRow.histSeqNo || ''; |
||||
|
|
||||
|
// 获取上机数量(从行数据的 transQty 字段) |
||||
|
const transQty = parseFloat(materialRow.transQty); |
||||
|
this.pageData.onMachineQty = isNaN(transQty) ? 0 : transQty; |
||||
|
// 重置接卷数量、剩余数量和备注 |
||||
|
this.pageData.returnQty = 0; |
||||
|
this.pageData.remainQty = this.pageData.onMachineQty; |
||||
|
this.pageData.remark = ''; |
||||
|
|
||||
|
this.titleCon = '材料拼卷'; |
||||
|
}, |
||||
|
|
||||
|
/*关闭modal*/ |
||||
|
closeDialog(){ |
||||
|
//刷新报工的页面 |
||||
|
this.$emit('refreshPageData'); |
||||
|
//关闭当前的页面 |
||||
|
this.$emit('update:visible', false); |
||||
|
}, |
||||
|
|
||||
|
/*计算剩余数量*/ |
||||
|
calculateRemainQty() { |
||||
|
const onMachineQty = parseFloat(this.pageData.onMachineQty) || 0; |
||||
|
const returnQty = parseFloat(this.pageData.returnQty) || 0; |
||||
|
this.pageData.remainQty = onMachineQty - returnQty; |
||||
|
}, |
||||
|
|
||||
|
/*提交接卷*/ |
||||
|
submitMaterialRollUp() { |
||||
|
// 如果没有填写接卷数量,默认为0 |
||||
|
if (!this.pageData.returnQty || this.pageData.returnQty === '' || this.pageData.returnQty < 0) { |
||||
|
this.pageData.returnQty = 0; |
||||
|
} |
||||
|
|
||||
|
// 计算剩余数量 |
||||
|
this.calculateRemainQty(); |
||||
|
|
||||
|
// 验证剩余数量必须大于等于0 |
||||
|
if (this.pageData.remainQty < 0) { |
||||
|
this.$message.warning('拼卷数量不能大于上机数量!'); |
||||
|
return false; |
||||
|
} |
||||
|
|
||||
|
// 构建提交数据(只传接卷数量和备注,不传上机数量和剩余数量) |
||||
|
const submitData = { |
||||
|
site: this.pageData.site, |
||||
|
orderNo: this.pageData.orderNo, |
||||
|
itemNo: this.pageData.itemNo, |
||||
|
seqNo: this.pageData.seqNo, |
||||
|
rollNo: this.pageData.rmRollNo, |
||||
|
returnQty: this.pageData.returnQty, |
||||
|
histSeqNo: this.pageData.histSeqNo, |
||||
|
operatorId: this.pageData.operatorId, |
||||
|
remark: this.pageData.remark || '' // 备注(可选,默认为空字符串) |
||||
|
}; |
||||
|
|
||||
|
// 调用后端API(调用 MaterialProcessRollUp 存储过程) |
||||
|
materialProcessRollUp(submitData).then(({data}) => { |
||||
|
//判断是否存在异常 |
||||
|
if(data.code == 500 || data.code == 400){ |
||||
|
this.$message.error(data.msg || data.message); |
||||
|
} else if (data.code == 201) { |
||||
|
// code=201 表示需要打印标签 |
||||
|
this.$message.success(data.msg || '操作成功'); |
||||
|
|
||||
|
// 获取打印参数并打印(存储过程返回的打印参数在printData中) |
||||
|
if (data.printData) { |
||||
|
// 将单个打印数据对象包装成数组 |
||||
|
const printDataList = [data.printData]; |
||||
|
this.executePrint(printDataList); |
||||
|
} else { |
||||
|
console.warn('未获取到打印参数'); |
||||
|
} |
||||
|
|
||||
|
//关闭当前的页面 |
||||
|
this.closeDialog(); |
||||
|
} else { |
||||
|
//先提示 后关闭 |
||||
|
this.$message.success(data.msg || data.message || '操作成功'); |
||||
|
//关闭当前的页面 |
||||
|
this.closeDialog(); |
||||
|
} |
||||
|
}).catch((error) => { |
||||
|
this.$message.error('操作失败:' + (error.message || '未知错误')); |
||||
|
}); |
||||
|
}, |
||||
|
|
||||
|
/** |
||||
|
* 执行打印(直接使用存储过程返回的打印参数) |
||||
|
* @param {Array} printDataList - 存储过程返回的打印数据列表 |
||||
|
*/ |
||||
|
executePrint(printDataList) { |
||||
|
try { |
||||
|
// 1. 获取 LODOP 打印控件 |
||||
|
const LODOP = getLodop(); |
||||
|
if (!LODOP) { |
||||
|
this.$message.warning('无法连接到打印控件,跳过打印'); |
||||
|
return; |
||||
|
} |
||||
|
|
||||
|
// 2. 获取默认打印机 |
||||
|
const printerCount = LODOP.GET_PRINTER_COUNT(); |
||||
|
if (printerCount === 0) { |
||||
|
this.$message.warning('未检测到打印机,跳过打印'); |
||||
|
return; |
||||
|
} |
||||
|
const defaultPrinterName = LODOP.GET_PRINTER_NAME(0); |
||||
|
|
||||
|
// 3. 检查打印数据中的labelNo(标签模板编号) |
||||
|
if (!printDataList || printDataList.length === 0) { |
||||
|
console.warn('打印数据为空'); |
||||
|
return; |
||||
|
} |
||||
|
|
||||
|
// 获取第一条数据的labelNo |
||||
|
const labelNo = printDataList[0].labelNo; |
||||
|
if (!labelNo) { |
||||
|
console.warn('未找到标签模板编号'); |
||||
|
return; |
||||
|
} |
||||
|
|
||||
|
// 4. 执行模板打印 |
||||
|
this.executePrintWithTemplate(LODOP, printDataList, labelNo, defaultPrinterName); |
||||
|
|
||||
|
this.$message.success('标签打印任务已发送!'); |
||||
|
|
||||
|
} catch (error) { |
||||
|
console.error('打印失败:', error); |
||||
|
this.$message.warning('打印失败: ' + error.message); |
||||
|
} |
||||
|
}, |
||||
|
|
||||
|
/** |
||||
|
* 执行模板打印 |
||||
|
* @param {Object} LODOP - 打印控件对象 |
||||
|
* @param {Array} printDataList - 打印数据列表 |
||||
|
* @param {String} labelNo - 标签模板编号 (A001/A002/A003) |
||||
|
* @param {String} printerName - 打印机名称 |
||||
|
*/ |
||||
|
executePrintWithTemplate(LODOP, printDataList, labelNo, printerName) { |
||||
|
LODOP.PRINT_INIT('材料拼卷标签打印'); |
||||
|
|
||||
|
// 设置打印模式,隐藏水印 |
||||
|
LODOP.SET_PRINT_MODE("PRINT_NOCOLLATE", true); |
||||
|
|
||||
|
// 设置打印机 |
||||
|
LODOP.SET_PRINTER_INDEX(printerName); |
||||
|
|
||||
|
// 循环打印每个标签 |
||||
|
for (let i = 0; i < printDataList.length; i++) { |
||||
|
const printData = printDataList[i]; |
||||
|
const isNewPage = i > 0; |
||||
|
// 根据 labelNo 调用不同的打印方法(来自 labelPrintTemplates mixin) |
||||
|
if (labelNo === 'A001') { |
||||
|
this.printLabelA001(LODOP, printData, isNewPage); |
||||
|
} else if (labelNo === 'A002') { |
||||
|
this.printLabelA002(LODOP, printData, isNewPage); |
||||
|
} else if (labelNo === 'A003') { |
||||
|
this.printLabelA003(LODOP, printData, isNewPage); |
||||
|
} else { |
||||
|
console.warn(`未知的标签模板:${labelNo}`); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
// 预览打印(避免水印) |
||||
|
LODOP.PREVIEW(); |
||||
|
}, |
||||
|
}, |
||||
|
} |
||||
|
</script> |
||||
|
|
||||
|
<style scoped lang="scss"> |
||||
|
.numInput /deep/ .el-input__inner{ |
||||
|
text-align: right; |
||||
|
} |
||||
|
/deep/ .inlineNumber input::-webkit-outer-spin-button, |
||||
|
/deep/ .inlineNumber input::-webkit-inner-spin-button { |
||||
|
-webkit-appearance: none; |
||||
|
|
||||
|
} |
||||
|
/deep/ .inlineNumber input[type="number"]{ |
||||
|
-moz-appearance: textfield; |
||||
|
padding-right: 5px !important; |
||||
|
} |
||||
|
|
||||
|
// 材料拼卷对话框样式 |
||||
|
.material-dialog { |
||||
|
::v-deep .el-dialog { |
||||
|
border-radius: 8px; |
||||
|
overflow: hidden; |
||||
|
|
||||
|
.el-dialog__header { |
||||
|
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); |
||||
|
padding: 18px 20px; |
||||
|
|
||||
|
.el-dialog__title { |
||||
|
color: #fff; |
||||
|
font-size: 16px; |
||||
|
font-weight: 600; |
||||
|
} |
||||
|
|
||||
|
.el-dialog__headerbtn { |
||||
|
.el-dialog__close { |
||||
|
color: #fff; |
||||
|
font-size: 18px; |
||||
|
|
||||
|
&:hover { |
||||
|
color: #f0f0f0; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
.el-dialog__body { |
||||
|
padding: 25px; |
||||
|
background-color: #f8f9fa; |
||||
|
} |
||||
|
|
||||
|
.el-dialog__footer { |
||||
|
padding: 15px 20px; |
||||
|
background-color: #fff; |
||||
|
border-top: 1px solid #e9ecef; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
.material-content { |
||||
|
.form-item-enhanced { |
||||
|
margin-bottom: 10px; |
||||
|
|
||||
|
::v-deep .el-form-item__label { |
||||
|
color: #495057; |
||||
|
font-weight: 500; |
||||
|
font-size: 14px; |
||||
|
margin-bottom: 8px; |
||||
|
} |
||||
|
|
||||
|
::v-deep .el-input { |
||||
|
.el-input__inner { |
||||
|
border-radius: 6px; |
||||
|
border: 1px solid #dee2e6; |
||||
|
transition: all 0.3s; |
||||
|
height: 42px; |
||||
|
line-height: 42px; |
||||
|
font-size: 15px; |
||||
|
|
||||
|
&:focus { |
||||
|
border-color: #667eea; |
||||
|
box-shadow: 0 0 0 3px rgba(102, 126, 234, 0.1); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
// 文本域样式 |
||||
|
::v-deep .el-textarea { |
||||
|
.el-textarea__inner { |
||||
|
border-radius: 6px; |
||||
|
border: 1px solid #dee2e6; |
||||
|
transition: all 0.3s; |
||||
|
font-size: 14px; |
||||
|
padding: 8px 12px; |
||||
|
line-height: 1.5; |
||||
|
|
||||
|
&:focus { |
||||
|
border-color: #667eea; |
||||
|
box-shadow: 0 0 0 3px rgba(102, 126, 234, 0.1); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
// 剩余数量为负数时的红色警告样式 |
||||
|
::v-deep .remain-negative { |
||||
|
.el-input__inner { |
||||
|
color: #f56c6c; |
||||
|
font-weight: 600; |
||||
|
border-color: #f56c6c; |
||||
|
background-color: #fef0f0; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
// 物料信息卡片样式 - 白色框连起来 |
||||
|
.material-info-card { |
||||
|
background: linear-gradient(135deg, #667eea15 0%, #764ba215 100%); |
||||
|
border-radius: 8px; |
||||
|
padding: 16px; |
||||
|
margin-bottom: 20px; |
||||
|
border: 1px solid #e3e8f0; |
||||
|
box-shadow: 0 2px 8px rgba(102, 126, 234, 0.08); |
||||
|
animation: fadeInDown 0.5s ease-out; |
||||
|
|
||||
|
.info-header { |
||||
|
display: flex; |
||||
|
align-items: center; |
||||
|
margin-bottom: 12px; |
||||
|
padding-bottom: 10px; |
||||
|
border-bottom: 1px solid #dee2e6; |
||||
|
|
||||
|
i { |
||||
|
font-size: 18px; |
||||
|
color: #667eea; |
||||
|
margin-right: 8px; |
||||
|
} |
||||
|
|
||||
|
span { |
||||
|
font-size: 14px; |
||||
|
font-weight: 600; |
||||
|
color: #495057; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
.info-content { |
||||
|
background-color: rgba(255, 255, 255, 0.8); |
||||
|
border-radius: 4px; |
||||
|
padding: 12px; |
||||
|
|
||||
|
.info-row { |
||||
|
display: flex; |
||||
|
align-items: center; |
||||
|
padding: 4px 0; |
||||
|
|
||||
|
&:not(:last-child) { |
||||
|
border-bottom: 1px dashed #e9ecef; |
||||
|
} |
||||
|
|
||||
|
.info-label { |
||||
|
font-size: 13px; |
||||
|
color: #6c757d; |
||||
|
min-width: 90px; |
||||
|
font-weight: 500; |
||||
|
} |
||||
|
|
||||
|
.info-value { |
||||
|
font-size: 13px; |
||||
|
color: #212529; |
||||
|
font-weight: 600; |
||||
|
flex: 1; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
// 拼卷设置区域 |
||||
|
.return-settings { |
||||
|
background: #fff; |
||||
|
border-radius: 8px; |
||||
|
padding: 16px; |
||||
|
border: 1px solid #e3e8f0; |
||||
|
box-shadow: 0 2px 8px rgba(102, 126, 234, 0.05); |
||||
|
} |
||||
|
|
||||
|
// 底部按钮样式 |
||||
|
.dialog-footer { |
||||
|
display: flex; |
||||
|
justify-content: center; |
||||
|
gap: 12px; |
||||
|
padding: 0; |
||||
|
|
||||
|
.action-btn { |
||||
|
min-width: 80px; |
||||
|
padding: 6px 16px; |
||||
|
border-radius: 16px; |
||||
|
font-size: 13px; |
||||
|
font-weight: 500; |
||||
|
cursor: pointer; |
||||
|
transition: all 0.2s ease; |
||||
|
display: inline-flex; |
||||
|
align-items: center; |
||||
|
justify-content: center; |
||||
|
gap: 4px; |
||||
|
|
||||
|
i { |
||||
|
font-size: 13px; |
||||
|
} |
||||
|
|
||||
|
&.primary { |
||||
|
background: #17B3A3; |
||||
|
border: none; |
||||
|
color: white; |
||||
|
|
||||
|
&:hover { |
||||
|
background: #13998b; |
||||
|
box-shadow: 0 4px 12px rgba(23, 179, 163, 0.4); |
||||
|
transform: translateY(-1px); |
||||
|
} |
||||
|
|
||||
|
&:active { |
||||
|
transform: translateY(0); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
&.secondary { |
||||
|
background: white; |
||||
|
border: 1px solid #17B3A3; |
||||
|
color: #17B3A3; |
||||
|
|
||||
|
&:hover { |
||||
|
background: #17B3A3; |
||||
|
color: white; |
||||
|
} |
||||
|
|
||||
|
&:active { |
||||
|
transform: scale(0.98); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
// 动画效果 |
||||
|
@keyframes fadeInDown { |
||||
|
from { |
||||
|
opacity: 0; |
||||
|
transform: translateY(-10px); |
||||
|
} |
||||
|
to { |
||||
|
opacity: 1; |
||||
|
transform: translateY(0); |
||||
|
} |
||||
|
} |
||||
|
</style> |
||||
|
|
||||
Write
Preview
Loading…
Cancel
Save
Reference in new issue