457 行
22 KiB
HTML
457 行
22 KiB
HTML
<link rel="stylesheet" href="__CDN__/assets/element-ui-2.15.14/css/index.css">
|
||
<link href="/assets/css/sweetalert.css" rel="stylesheet">
|
||
<link rel="stylesheet" href="__CDN__/assets/css/vvv.css">
|
||
<style>
|
||
.quality-edit-page {
|
||
padding: 16px;
|
||
background: #f4f6f9;
|
||
min-height: calc(100vh - 40px);
|
||
}
|
||
.page-header-card {
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: space-between;
|
||
background: #fff;
|
||
padding: 14px 20px;
|
||
border-radius: 6px;
|
||
box-shadow: 0 1px 4px rgba(0,21,41,.08);
|
||
margin-bottom: 16px;
|
||
}
|
||
.page-header-left {
|
||
display: flex;
|
||
align-items: center;
|
||
gap: 12px;
|
||
}
|
||
.page-header-title {
|
||
font-size: 16px;
|
||
font-weight: 600;
|
||
color: #1f2d3d;
|
||
}
|
||
.page-body-card {
|
||
background: #fff;
|
||
padding: 24px 24px 80px 24px;
|
||
border-radius: 6px;
|
||
box-shadow: 0 1px 4px rgba(0,21,41,.08);
|
||
}
|
||
.quality-editor-card {
|
||
padding: 14px 16px 10px;
|
||
border: 1px solid #e4e7ed;
|
||
border-radius: 8px;
|
||
background: #fff;
|
||
margin-top: 6px;
|
||
}
|
||
.quality-editor-toolbar {
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: space-between;
|
||
gap: 16px;
|
||
margin-bottom: 12px;
|
||
padding: 10px 14px;
|
||
border-radius: 6px;
|
||
background: #f0f9ff;
|
||
color: #5f6b7a;
|
||
font-size: 13px;
|
||
line-height: 1.6;
|
||
}
|
||
.quality-legend {
|
||
display: flex;
|
||
flex-wrap: wrap;
|
||
gap: 10px;
|
||
white-space: nowrap;
|
||
}
|
||
.quality-legend span {
|
||
padding: 2px 8px;
|
||
border-radius: 4px;
|
||
font-size: 12px;
|
||
}
|
||
.quality-legend .good { background: #eaf8f0; color: #16844a; }
|
||
.quality-legend .warn { background: #fef7e7; color: #946200; }
|
||
.quality-legend .bad { background: #fdeeee; color: #c0392b; }
|
||
.quality-rule-ranges {
|
||
display: flex;
|
||
flex-direction: column;
|
||
gap: 2px;
|
||
font-size: 12px;
|
||
margin-top: 4px;
|
||
}
|
||
.quality-direction-help {
|
||
margin-top: 10px;
|
||
font-size: 12px;
|
||
color: #909399;
|
||
}
|
||
.page-footer-bar {
|
||
position: fixed;
|
||
left: 0;
|
||
right: 0;
|
||
bottom: 0;
|
||
background: #fff;
|
||
padding: 12px 30px;
|
||
border-top: 1px solid #e4e7ed;
|
||
box-shadow: 0 -3px 10px rgba(0, 0, 0, .05);
|
||
display: flex;
|
||
justify-content: flex-end;
|
||
gap: 12px;
|
||
z-index: 100;
|
||
}
|
||
</style>
|
||
|
||
<div id="vue" v-cloak class="quality-edit-page">
|
||
<div class="page-header-card">
|
||
<div class="page-header-left">
|
||
<el-button size="small" icon="el-icon-back" @click="goBack">返回列表</el-button>
|
||
<span class="page-header-title">{{ formData.id ? '编辑检测报告' : '添加检测报告' }}</span>
|
||
</div>
|
||
<div>
|
||
<el-button size="small" type="primary" :loading="submitting" icon="el-icon-check" @click="submit">保存提交</el-button>
|
||
<el-button size="small" @click="goBack">取消</el-button>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="page-body-card">
|
||
<el-form ref="form" :rules="rules" :model="formData" label-width="120px">
|
||
<el-row :gutter="20">
|
||
<el-col :xs="24" :sm="12" :md="8">
|
||
<el-form-item label="所属库区:" required>
|
||
<el-select v-model="formSite" @change="formSiteChanged" placeholder="请选择库区" style="width: 100%;">
|
||
<el-option v-for="site in siteOptions" :key="site.id" :value="site.id" :label="site.name"></el-option>
|
||
</el-select>
|
||
</el-form-item>
|
||
</el-col>
|
||
<el-col :xs="24" :sm="12" :md="8">
|
||
<el-form-item label="所属仓库:" prop="gid">
|
||
<el-select @change="handleGranaryChange" style="width: 100%;" v-model="formData.gid" filterable clearable placeholder="请选择所属仓库">
|
||
<el-option v-for="item in siteGranaries" :key="item.id" :label="granaryLabel(item)" :value="item.id"></el-option>
|
||
</el-select>
|
||
</el-form-item>
|
||
</el-col>
|
||
<el-col :xs="24" :sm="12" :md="8">
|
||
<el-form-item label="品种类型:">
|
||
<el-tag type="info" size="medium">{{ typeName || '随仓库自动匹配' }}</el-tag>
|
||
</el-form-item>
|
||
</el-col>
|
||
</el-row>
|
||
|
||
<el-row :gutter="20">
|
||
<el-col :xs="24" :sm="12" :md="8">
|
||
<el-form-item label="记录日期:" prop="record_date">
|
||
<el-date-picker style="width: 100%;" value-format="yyyy-MM" v-model="formData.record_date" type="month" placeholder="请选择记录日期"></el-date-picker>
|
||
</el-form-item>
|
||
</el-col>
|
||
<el-col :xs="24" :sm="12" :md="8">
|
||
<el-form-item label="季节:" prop="season">
|
||
<el-radio-group v-model="formData.season" size="small">
|
||
<el-radio-button :label="1">春季</el-radio-button>
|
||
<el-radio-button :label="2">秋季</el-radio-button>
|
||
<el-radio-button :label="3">满仓</el-radio-button>
|
||
</el-radio-group>
|
||
</el-form-item>
|
||
</el-col>
|
||
<el-col :xs="24" :sm="12" :md="8">
|
||
<el-form-item label="排序:" prop="sort">
|
||
<el-input type="number" placeholder="排序序号" style="width: 100%;" v-model="formData.sort"></el-input>
|
||
</el-form-item>
|
||
</el-col>
|
||
</el-row>
|
||
|
||
<el-form-item label="检测参数:" required style="margin-top: 10px;">
|
||
<div class="quality-editor-card">
|
||
<div class="quality-editor-toolbar">
|
||
<div><strong>录入提示:</strong>先填实测值、预警值和警告值,再选择指标偏好。大屏显示列可开启或关闭该参数在大屏上的展示。等于阈值时归入较低一级。</div>
|
||
<div class="quality-legend" aria-label="颜色规则">
|
||
<span class="good">绿 · 达标</span>
|
||
<span class="warn">黄 · 预警</span>
|
||
<span class="bad">红 · 警告</span>
|
||
</div>
|
||
</div>
|
||
|
||
<el-table :data="currentParams" border highlight-current-row style="width: 100%;">
|
||
<el-table-column prop="num" width="60" label="序号" align="center"></el-table-column>
|
||
<el-table-column prop="name" min-width="150" label="检测项目" align="center"></el-table-column>
|
||
<el-table-column prop="unit" width="120" label="单位" align="center">
|
||
<template scope="scope">
|
||
<el-input style="width: 95px;" placeholder="单位" size="small" maxlength="15" v-model="scope.row.unit"></el-input>
|
||
</template>
|
||
</el-table-column>
|
||
<el-table-column prop="val" width="140" label="值" align="center">
|
||
<template scope="scope">
|
||
<el-input style="width: 115px;" placeholder="输入检测值" size="small" maxlength="50" v-model="scope.row.val"></el-input>
|
||
</template>
|
||
</el-table-column>
|
||
<el-table-column prop="warning" width="140" label="预警值" align="center">
|
||
<template scope="scope">
|
||
<el-input style="width: 115px;" placeholder="输入预警值" size="small" maxlength="50" v-model="scope.row.warning"></el-input>
|
||
</template>
|
||
</el-table-column>
|
||
<el-table-column prop="alert" width="140" label="警告值" align="center">
|
||
<template scope="scope">
|
||
<el-input style="width: 115px;" placeholder="输入警告值" size="small" maxlength="50" v-model="scope.row.alert"></el-input>
|
||
</template>
|
||
</el-table-column>
|
||
<el-table-column prop="is_number" width="110" label="大屏显示" align="center">
|
||
<template scope="scope">
|
||
<el-button @click="handelIsNumber(scope.$index, 2)" size="mini" v-if="scope.row.is_number == 1" type="success" icon="el-icon-check">显示</el-button>
|
||
<el-button @click="handelIsNumber(scope.$index, 1)" size="mini" v-else type="warning" icon="el-icon-close">隐藏</el-button>
|
||
</template>
|
||
</el-table-column>
|
||
<el-table-column width="280" label="指标偏好与颜色规则" align="left">
|
||
<template scope="scope">
|
||
<template v-if="isNumericRule(scope.row)">
|
||
<el-button-group class="quality-direction-toggle" :aria-label="'选择' + scope.row.name + '的指标偏好'">
|
||
<el-button size="mini" :type="ruleDirection(scope.row) === 'lower' ? 'success' : 'info'"
|
||
:plain="ruleDirection(scope.row) !== 'lower'"
|
||
@click="setRuleDirection(scope.row, 'lower')">越大越好</el-button>
|
||
<el-button size="mini" :type="ruleDirection(scope.row) === 'upper' ? 'success' : 'info'"
|
||
:plain="ruleDirection(scope.row) !== 'upper'"
|
||
@click="setRuleDirection(scope.row, 'upper')">越小越好</el-button>
|
||
</el-button-group>
|
||
<div v-if="ruleError(scope.row)" style="color: #c0392b; margin-top: 6px;">{{ruleError(scope.row)}}</div>
|
||
<div v-else class="quality-rule-ranges">
|
||
<span style="color: #16844a;">绿 {{ruleRanges(scope.row)[0]}}</span>
|
||
<span style="color: #946200;">黄 {{ruleRanges(scope.row)[1]}}</span>
|
||
<span style="color: #c0392b;">红 {{ruleRanges(scope.row)[2]}}</span>
|
||
</div>
|
||
</template>
|
||
<span v-else-if="ruleError(scope.row)" style="color: #c0392b;">{{ruleError(scope.row)}}</span>
|
||
<span v-else>文字指标,按检测结果判定</span>
|
||
</template>
|
||
</el-table-column>
|
||
</el-table>
|
||
<div class="quality-direction-help">“越大越好”:低于预警值会触发风险;“越小越好”:高于预警值会触发风险。文字指标按检测结果判定。</div>
|
||
</div>
|
||
</el-form-item>
|
||
</el-form>
|
||
</div>
|
||
|
||
<div class="page-footer-bar">
|
||
<el-button @click="goBack" icon="el-icon-close">返回列表</el-button>
|
||
<el-button type="primary" :loading="submitting" @click="submit" icon="el-icon-check">保存提交</el-button>
|
||
</div>
|
||
</div>
|
||
|
||
<script src="__CDN__/assets/element-ui-2.15.14/js/vue.js"></script>
|
||
<script src="__CDN__/assets/element-ui-2.15.14/js/index.js"></script>
|
||
<script src="/assets/js/sweetalert.min.js"></script>
|
||
<script src="__CDN__/assets/js/jquery-2.1.1.min.js"></script>
|
||
|
||
<script>
|
||
var SERVER_DATA = {
|
||
item: {:json_encode($item, JSON_UNESCAPED_UNICODE)},
|
||
granaryList: {:json_encode($granaryList, JSON_UNESCAPED_UNICODE)},
|
||
typeList: {:json_encode($typeList, JSON_UNESCAPED_UNICODE)},
|
||
siteOptions: {:json_encode($siteOptions, JSON_UNESCAPED_UNICODE)}
|
||
};
|
||
|
||
new Vue({
|
||
el: '#vue',
|
||
data: function () {
|
||
var rawItem = SERVER_DATA.item;
|
||
var granaryList = SERVER_DATA.granaryList || [];
|
||
var typeList = SERVER_DATA.typeList || {};
|
||
var siteOptions = SERVER_DATA.siteOptions || [];
|
||
|
||
var formSite = '';
|
||
var formData = {
|
||
id: 0,
|
||
gid: '',
|
||
type: 'rapeseed',
|
||
record_date: '',
|
||
season: 1,
|
||
sort: '',
|
||
content: []
|
||
};
|
||
var typeName = '';
|
||
|
||
if (rawItem) {
|
||
formSite = (rawItem.granary && rawItem.granary.site) ? rawItem.granary.site : ((siteOptions[0] || {}).id || '');
|
||
formData = {
|
||
id: rawItem.id,
|
||
gid: rawItem.gid,
|
||
type: rawItem.type,
|
||
season: rawItem.season,
|
||
record_date: rawItem.year + '-' + (rawItem.month < 10 ? '0' + parseInt(rawItem.month) : rawItem.month),
|
||
sort: rawItem.sort,
|
||
content: []
|
||
};
|
||
typeName = (rawItem.granary && rawItem.granary.varieties) ? rawItem.granary.varieties : '';
|
||
if (typeList[rawItem.type]) {
|
||
typeList[rawItem.type]['content'] = JSON.parse(JSON.stringify(rawItem.testing_params || []));
|
||
}
|
||
} else {
|
||
formSite = (siteOptions[0] || {}).id || '';
|
||
}
|
||
|
||
return {
|
||
siteOptions: siteOptions,
|
||
granaryList: granaryList,
|
||
typeList: typeList,
|
||
formSite: formSite,
|
||
typeName: typeName,
|
||
formData: formData,
|
||
submitting: false,
|
||
rules: {
|
||
gid: [{ required: true, message: '请选择所属仓库', trigger: 'blur' }],
|
||
record_date: [{ required: true, message: '请选择记录日期', trigger: 'blur' }]
|
||
}
|
||
};
|
||
},
|
||
computed: {
|
||
siteGranaries: function () {
|
||
var self = this;
|
||
if (!self.formSite) return self.granaryList;
|
||
return self.granaryList.filter(function (item) {
|
||
return item.site === self.formSite;
|
||
});
|
||
},
|
||
currentParams: function () {
|
||
var group = this.typeList[this.formData.type];
|
||
return group ? group.content : [];
|
||
}
|
||
},
|
||
created: function () {
|
||
if (!this.formData.id && this.siteGranaries.length > 0) {
|
||
var first = this.siteGranaries[0];
|
||
this.formData.gid = first.id;
|
||
this.handleGranaryChange(first.id);
|
||
}
|
||
},
|
||
methods: {
|
||
granaryLabel: function (item) {
|
||
return (item.site_name ? item.site_name + ' · ' : '') + item.name + (item.varieties ? ' (' + item.varieties + ')' : '');
|
||
},
|
||
formSiteChanged: function () {
|
||
var valid = this.siteGranaries.some(function (g) { return g.id === this.formData.gid; }.bind(this));
|
||
if (!valid && this.siteGranaries.length > 0) {
|
||
this.formData.gid = this.siteGranaries[0].id;
|
||
this.handleGranaryChange(this.formData.gid);
|
||
} else if (this.siteGranaries.length === 0) {
|
||
this.formData.gid = '';
|
||
this.typeName = '';
|
||
}
|
||
},
|
||
handleGranaryChange: function (gid) {
|
||
var item = this.granaryList.find(function (v) { return v.id === gid; });
|
||
if (!item) return;
|
||
this.typeName = item.varieties || '';
|
||
this.formData.type = item.type || 'rapeseed';
|
||
},
|
||
handelIsNumber: function (index, val) {
|
||
var params = this.currentParams;
|
||
if (params && params[index]) {
|
||
this.$set(params[index], 'is_number', val);
|
||
}
|
||
},
|
||
isRuleNumber: function (val) {
|
||
return (typeof val === 'string' || typeof val === 'number')
|
||
&& /^[+-]?(?:\d+\.?\d*|\.\d+)(?:[eE][+-]?\d+)?$/.test(String(val).trim())
|
||
&& Number.isFinite(Number(val));
|
||
},
|
||
isNumericRule: function (item) {
|
||
return this.isRuleNumber(item.warning) && this.isRuleNumber(item.alert);
|
||
},
|
||
ruleDirection: function (item) {
|
||
if (item.direction === 'upper' || item.direction === 'lower') return item.direction;
|
||
return (this.isNumericRule(item) && Number(item.warning) > Number(item.alert)) ? 'lower' : 'upper';
|
||
},
|
||
setRuleDirection: function (item, dir) {
|
||
this.$set(item, 'direction', dir);
|
||
},
|
||
ruleRanges: function (item) {
|
||
var w = item.warning, a = item.alert;
|
||
return this.ruleDirection(item) === 'upper'
|
||
? ['当前值 ≤ ' + w, w + ' < 当前值 ≤ ' + a, '当前值 > ' + a]
|
||
: ['当前值 ≥ ' + w, a + ' ≤ 当前值 < ' + w, '当前值 < ' + a];
|
||
},
|
||
ruleError: function (item) {
|
||
var expectsNumeric = item.rule_numeric === true || Number(item.is_number) === 1
|
||
|| this.isRuleNumber(item.warning) || this.isRuleNumber(item.alert);
|
||
if (expectsNumeric && !this.isNumericRule(item)) return '预警值和警告值必须都是有限数字';
|
||
if (!this.isNumericRule(item)) return '';
|
||
if (!this.isRuleNumber(item.val)
|
||
&& !/^(?:\/|--?|未检测|未提供|暂无|未检出|未检出\s*ND|ND)$/i.test(String(item.val ?? '').trim())) {
|
||
return '检测值必须是有限数字,缺测可填 /';
|
||
}
|
||
var upper = this.ruleDirection(item) === 'upper';
|
||
return (upper && Number(item.warning) > Number(item.alert)) || (!upper && Number(item.warning) < Number(item.alert))
|
||
? (upper ? '越小越好指标要求:预警值 ≤ 警告值(高值预警)' : '越大越好指标要求:预警值 ≥ 警告值(低值预警)') : '';
|
||
},
|
||
goBack: function (refresh) {
|
||
if (typeof top !== 'undefined' && top && top.Backend && top.Backend.api && top.Backend.api.closetabs) {
|
||
if (refresh && top.$) {
|
||
var listIframe = top.$('.tab-pane iframe[src*="testing/index"], .tab-pane iframe[src*="testing"]');
|
||
if (listIframe.length && listIframe[0].contentWindow && listIframe[0].contentWindow.location) {
|
||
listIframe[0].contentWindow.location.reload();
|
||
}
|
||
}
|
||
var currentNav = top.$("#nav ul.nav-tabs li.active");
|
||
if (currentNav.length > 0) {
|
||
currentNav.find(".close-tab").trigger("click");
|
||
return;
|
||
}
|
||
}
|
||
if (window.history.length > 1) {
|
||
window.history.back();
|
||
} else {
|
||
window.location.href = 'testing/index';
|
||
}
|
||
},
|
||
submit: function () {
|
||
var self = this;
|
||
self.$refs.form.validate(function (valid) {
|
||
if (!valid) return false;
|
||
var content = self.currentParams;
|
||
for (var i = 0; i < content.length; i++) {
|
||
var p = content[i];
|
||
var err = self.ruleError(p);
|
||
if (err) {
|
||
swal({ title: '温馨提示', text: p.name + ':' + err, type: 'warning' });
|
||
return false;
|
||
}
|
||
self.$set(p, 'direction', self.ruleDirection(p));
|
||
if (p.val === '' || p.val === null || p.val === undefined) {
|
||
swal({ title: '温馨提示', text: '请您输入' + p.name + '值', type: 'warning' });
|
||
return false;
|
||
}
|
||
if (p.warning === '') {
|
||
swal({ title: '温馨提示', text: '请您输入' + p.name + '预警值', type: 'warning' });
|
||
return false;
|
||
}
|
||
if (p.alert === '') {
|
||
swal({ title: '温馨提示', text: '请您输入' + p.name + '警告值', type: 'warning' });
|
||
return false;
|
||
}
|
||
}
|
||
|
||
self.formData.content = content;
|
||
self.submitting = true;
|
||
|
||
$.ajax({
|
||
url: 'testing/add',
|
||
type: 'POST',
|
||
data: self.formData,
|
||
dataType: 'json',
|
||
success: function (res) {
|
||
self.submitting = false;
|
||
if (res.code === 200) {
|
||
swal({
|
||
title: '保存成功',
|
||
text: res.msg || '质检报告已成功保存',
|
||
type: 'success',
|
||
confirmButtonColor: '#7367f0',
|
||
confirmButtonText: '确定'
|
||
}, function () {
|
||
self.goBack(true);
|
||
});
|
||
} else {
|
||
swal({ title: '保存失败', text: res.msg, type: 'error' });
|
||
}
|
||
},
|
||
error: function () {
|
||
self.submitting = false;
|
||
swal({ title: '网络错误', text: '提交失败,请稍后重试', type: 'error' });
|
||
}
|
||
});
|
||
});
|
||
}
|
||
}
|
||
});
|
||
</script> |