Browse Source

feat:[模板管理][没输入内容的时候标红]

master
luojie 5 days ago
parent
commit
8ddb734499
5 changed files with 208 additions and 57 deletions
  1. +66
    -33
      src/components/Template/BaseInfoFormPcakge.vue
  2. +50
    -13
      src/components/Template/CustomTable.vue
  3. +15
    -3
      src/components/Template/DecimalInput.vue
  4. +75
    -6
      src/components/Template/HandleFormItem.vue
  5. +2
    -2
      vue.config.js

+ 66
- 33
src/components/Template/BaseInfoFormPcakge.vue View File

@ -9,12 +9,12 @@
<template v-if="sItem.type === 'input'">
<div class="form-title">{{ sItem.label }}</div>
<HandleFormItem @blur="onBlur(key, $event)" :item="sItem" v-model="formFields[key]"
@copy="onCopy(sItem, key)" />
@copy="onCopy(sItem, key)" :error="errors[key]" @update:error="errors[key] = false" />
</template>
<template v-else-if="sItem.type === 'inputNumber'">
<div class="form-title">{{ sItem.label }}</div>
<HandleFormItem type = "inputNumber" @blur="onBlur(key, $event)" :item="sItem" @input = "onInputNumberChange(key, $event)" v-model="formFields[key]"
@copy="onCopy(sItem, key)" />
@copy="onCopy(sItem, key)" :error="errors[key]" @update:error="errors[key] = false" />
</template>
</div>
</div>
@ -27,7 +27,7 @@
<div class="form-title">{{ sItem.label }}</div>
<div class="flex ">
<HandleFormItem type="select" :item="sItem" v-model="formFields[key]"
@copy="onCopy(sItem, key)" @change="onSelectChange(key, $event)" />
@copy="onCopy(sItem, key)" @change="onSelectChange(key, $event)" :error="errors[key]" @update:error="errors[key] = false" />
</div>
</div>
@ -36,7 +36,7 @@
<div class="form-title">其他</div>
<div class="flex">
<HandleFormItem @blur="onBlur(key, $event)" :item="getOtherItem(sItem)" v-model="formFields[sItem.otherCode]"
@copy="onCopy(sItem, key)" />
@copy="onCopy(sItem, key)" :error="errors[sItem.otherCode]" @update:error="errors[sItem.otherCode] = false" />
</div>
</div>
@ -54,19 +54,19 @@
<div class="form-title" v-if="sItem.label">{{ sItem.label }}</div>
<div v-if="sItem.type === 'dateTime'" class="flex1">
<HandleFormItem type="dateTime" :item="sItem" v-model="formFields[key]"
@copy="onCopy(sItem, key)" />
@copy="onCopy(sItem, key)" :error="errors[key]" @update:error="errors[key] = false" />
</div>
<div v-else-if="sItem.type === 'select'">
<HandleFormItem type="select" :item="sItem" v-model="formFields[key]"
@copy="onCopy(sItem, key)" @change="onSelectChange(key, $event)" />
@copy="onCopy(sItem, key)" @change="onSelectChange(key, $event)" :error="errors[key]" @update:error="errors[key] = false" />
</div>
<div v-else-if="sItem.type === 'input'">
<HandleFormItem @blur="onBlur(key, $event)" :item="sItem" v-model="formFields[key]"
@copy="onCopy(sItem, key)" />
@copy="onCopy(sItem, key)" :error="errors[key]" @update:error="errors[key] = false" />
</div>
<div v-else-if="sItem.type === 'textarea'">
<HandleFormItem @blur="onBlur(key, $event)" type="textarea" :item="sItem" v-model="formFields[key]"
@copy="onCopy(sItem, key)" />
@copy="onCopy(sItem, key)" :error="errors[key]" @update:error="errors[key] = false" />
</div>
</div>
</div>
@ -80,24 +80,24 @@
<div class="step-form-title" v-if="sItem.label">{{ sItem.label }}</div>
<div v-if="sItem.type === 'dateTime'" class="flex1">
<HandleFormItem type="dateTime" :item="sItem" v-model="formFields[key]"
@copy="onCopy(sItem, key)" />
@copy="onCopy(sItem, key)" :error="errors[key]" @update:error="errors[key] = false" />
</div>
<div v-else-if="sItem.type === 'select'" class="flex flex1">
<HandleFormItem type="select" :item="sItem" style="width: auto;flex:1" v-model="formFields[key]"
@copy="onCopy(sItem, key)" @change="onSelectChange(key, $event)" />
@copy="onCopy(sItem, key)" @change="onSelectChange(key, $event)" :error="errors[key]" @update:error="errors[key] = false" />
<div v-show="isShowOther(formFields[key])" class="flex flex1">
<div class="other-title">其他</div>
<div class="flex">
<HandleFormItem @blur="onBlur(key, $event)" class="sub-select" :item="getOtherItem(sItem)" v-model="formFields[sItem.otherCode]"
@copy="onCopy(sItem, key)" />
@copy="onCopy(sItem, key)" :error="errors[sItem.otherCode]" @update:error="errors[sItem.otherCode] = false" />
</div>
</div>
</div>
<div v-else-if="sItem.type === 'input'" class="flex flex1">
<HandleFormItem @blur="onBlur(key, $event)" class="flex1" :item="sItem" v-model="formFields[key]"
@copy="onCopy(sItem, key)" />
@copy="onCopy(sItem, key)" :error="errors[key]" @update:error="errors[key] = false" />
<HandleFormItem v-if="sItem.subType === 'select'" type="select" class="sub-select" :item="getSubItem(sItem)" v-model="formFields[sItem.subKey]"
@copy="onCopy(sItem, key)" @change="onSelectChange(sItem.subKey, $event)" />
@copy="onCopy(sItem, key)" @change="onSelectChange(sItem.subKey, $event)" :error="errors[sItem.subKey]" @update:error="errors[sItem.subKey] = false" />
<div v-else-if="sItem.subType === 'span'">{{ formFields[sItem.subKey] }}</div>
<HandleFormItem v-else-if="sItem.subType === 'clickable'" type="clickable" @clickable="handleClickable(sItem,$event)" class="sub-select" :item="getClickableItem(sItem)" :value="formFields[sItem.subKey]"
/>
@ -108,9 +108,9 @@
</div>
<div v-else-if="sItem.type === 'inputNumber'" class="flex flex1">
<HandleFormItem type = "inputNumber" @blur="onBlur(key, $event)" class="flex1" :item="sItem" @input = "onInputNumberChange(key, $event)" :value = "formFields[key]"
@copy="onCopy(sItem, key)" />
@copy="onCopy(sItem, key)" :error="errors[key]" @update:error="errors[key] = false" />
<HandleFormItem v-if="sItem.subType === 'select'" type="select" class="sub-select" :item="getSubItem(sItem)" v-model="formFields[sItem.subKey]"
@copy="onCopy(sItem, key)" @change="onSelectChange(sItem.subKey, $event)" />
@copy="onCopy(sItem, key)" @change="onSelectChange(sItem.subKey, $event)" :error="errors[sItem.subKey]" @update:error="errors[sItem.subKey] = false" />
<div v-else-if="sItem.subType === 'span'">{{ formFields[sItem.subKey] }}</div>
<HandleFormItem v-else-if="sItem.subType === 'clickable'" @clickable="handleClickable(sItem,$event)" type="clickable" class="sub-select" :item="getClickableItem(sItem)" :value="formFields[sItem.subKey]"
/>
@ -152,6 +152,7 @@ export default {
return {
formFields: {},//
allFieldsConfig: {},//config,
errors: {},//
};
},
watch: {
@ -187,13 +188,25 @@ export default {
},
onInputNumberChange(key, val){
this.formFields[key] = val;
//
if (this.errors[key]) {
this.$set(this.errors, key, false);
}
},
updateFormData(key, value){
this.formFields[key] = value;
//
if (this.errors[key]) {
this.$set(this.errors, key, false);
}
},
batchUpdateFormData(data){
Object.keys(data).forEach(key => {
this.formFields[key] = data[key];
//
if (this.errors[key]) {
this.$set(this.errors, key, false);
}
})
},
handleClickable(sItem,event){
@ -272,12 +285,12 @@ export default {
if (currentConfig.otherCode) {
const { otherCode } = currentConfig;
result[otherCode] = formData[otherCode] || '';
config[otherCode] = { label: "其他", type: "input" }
config[otherCode] = { label: "其他", parentKey:key, type: "input",fillType:currentConfig.fillType,otherCode }
}
if (currentConfig.subKey) {
const { subKey } = currentConfig;
result[subKey] = formData[subKey] || '';
config[subKey] = { label: currentConfig.label, type: currentConfig.subType }
config[subKey] = { label: currentConfig.label,subKey, type: currentConfig.subType,fillType:currentConfig.subFillType || currentConfig.fillType }
}
});
@ -287,11 +300,9 @@ export default {
}
}
});
console.log(result,"initResult")
//
this.formFields = result;
this.allFieldsConfig = config;
console.log(config,"config")
},
//
getDisabled() {
@ -313,28 +324,46 @@ export default {
getFormData() {
const { formFields, allFieldsConfig } = this;
const { templateStatus } = this.$store.state.template;
return new Promise((resolve,reject)=>{
for (const key in formFields) {
console.log(key,formFields[key])
if (!formFields[key]) {
const o = allFieldsConfig[key];
if (o.fillType == templateStatus && !o.disabled) {
//
this.errors = {};
const errors = {};
let firstError = null;
for (const key in allFieldsConfig) {
if (!formFields[key]) {
const o = allFieldsConfig[key];
if (o.label === "其他" && !this.isShowOther(formFields[o.parentKey])) {
continue
}
if (o.fillType == templateStatus && !o.disabled) {
//
errors[key] = true;
if (!firstError) {
let prefix = "";
if (o.type === "input" || o.type === "inputNumber" || o.type === "textarea") {
prefix = "填写"
prefix = "填写";
} else {
prefix = "选择"
prefix = "选择";
}
this.$message.error(`${o.label}还未${prefix}${prefix}后再提交`);
reject(`${o.label}还未${prefix}`);
return;
firstError = { label: o.label, prefix };
}
}
}
resolve(formFields)
})
}
//
this.errors = errors;
return new Promise((resolve, reject) => {
if (Object.keys(errors).length > 0) {
//
this.$message.error(`表单内容未填完,请填写后再提交`);
reject(`${firstError.label}还未${firstError.prefix}`);
} else {
resolve(formFields);
}
});
},
getFormDataByKey(key){
return this.formFields[key];
@ -355,6 +384,10 @@ export default {
this.formFields[key] = val;
// }
this.$emit("select", { key, value: val });
//
if (this.errors[key]) {
this.$set(this.errors, key, false);
}
},
//
onCopy(config, key) {

+ 50
- 13
src/components/Template/CustomTable.vue View File

@ -31,14 +31,14 @@
<div class="inner-table-cell">
<div>
<template v-if="col.bodyType === 'input'">
<HandleFormItem type="input" @blur = "onBlur(rowIndex, col.prop, $event)" @copy = "onCopy(rowIndex, col)" class="body-input" :item="getBodyItem(col,rowIndex)" v-model="row[col.prop]" @change="onBodyValueChange(rowIndex, colIndex, $event)" />
<HandleFormItem type="input" @blur = "onBlur(rowIndex, col.prop, $event)" @copy = "onCopy(rowIndex, col)" class="body-input" :item="getBodyItem(col,rowIndex)" v-model="row[col.prop]" @change="onBodyValueChange(rowIndex, colIndex, $event)" :error="hasError(rowIndex, colIndex, col.prop)" @update:error="onErrorUpdate(rowIndex, colIndex, col.prop, $event)" />
</template>
<template v-else-if="col.bodyType === 'inputNumber'">
<HandleFormItem type="inputNumber" @copy = "onCopy(rowIndex, col)" class="body-input-number" :item="getBodyItem(col,rowIndex)"
v-model="row[col.prop]" @blur = "onBlur(rowIndex, col.prop, $event)" @change="onBodyValueChange(rowIndex, colIndex, $event)" />
v-model="row[col.prop]" @blur = "onBlur(rowIndex, col.prop, $event)" @change="onBodyValueChange(rowIndex, colIndex, $event)" :error="hasError(rowIndex, colIndex, col.prop)" @update:error="onErrorUpdate(rowIndex, colIndex, col.prop, $event)" />
</template>
<template v-else-if="col.bodyType === 'select'">
<HandleFormItem type="select" class="body-select" @blur = "onBlur(rowIndex, col.prop, $event)" :item="getBodyItem(col,rowIndex)" v-model="row[col.prop]" @change="onBodyValueChange(rowIndex, colIndex, $event)" />
<HandleFormItem type="select" class="body-select" @blur = "onBlur(rowIndex, col.prop, $event)" :item="getBodyItem(col,rowIndex)" v-model="row[col.prop]" @change="onBodyValueChange(rowIndex, colIndex, $event)" :error="hasError(rowIndex, colIndex, col.prop)" @update:error="onErrorUpdate(rowIndex, colIndex, col.prop, $event)" />
</template>
<template v-else>
{{ row[col.prop] }}
@ -47,7 +47,7 @@
<div class="m-l-5" v-if="col.showBodySub">
<template v-if="col.bodySubType === 'inputNumber'">
<HandleFormItem type="inputNumber" @blur = "onSubBlur(rowIndex, col.bodySubKey, $event)" @copy = "onCopy(rowIndex, col)" :item="getBodySubItem(col)"
v-model="row[col.bodySubKey]" @change="onBodySubValueChange(rowIndex, colIndex, $event)" />
v-model="row[col.bodySubKey]" @change="onBodySubValueChange(rowIndex, colIndex, $event)" :error="hasError(rowIndex, colIndex, col.bodySubKey)" @update:error="onErrorUpdate(rowIndex, colIndex, col.bodySubKey, $event)" />
</template>
<template v-else>
{{ row[col.bodySubKey] }}
@ -110,7 +110,8 @@ export default {
data() {
return {
localDataSource: [],
headerSelectFields: {}
headerSelectFields: {},
formErrors: [] //
}
},
watch: {
@ -162,7 +163,7 @@ export default {
headerSelectFields: this.headerSelectFields,
})
}else{
this.$message.error(validateResult.errors[0].error);
this.$message.error("表单内容未填完,请填写后再提交");
reject(validateResult.errors[0].error)
}
})
@ -173,37 +174,43 @@ export default {
const templateStatus = this.$store.state.template.templateStatus;
const errors = [];
//
this.formErrors = [];
//
this.localDataSource.forEach((row, rowIndex) => {
//
this.columns.forEach((col, colIndex) => {
// fillType
if (col.bodyFillType === templateStatus || col.bodySubType === templateStatus) {
if (col.bodyFillType === templateStatus || col.bodySubFillType === templateStatus) {
//
const mainValue = row[col.prop];
if (this.isValueEmpty(mainValue) && !col.bodyDisabled) {
console.log(col,"col")
errors.push({
const errorItem = {
rowIndex,
colIndex,
field: col.prop,
label: col.label,
error: `请填写${col.label}`
});
};
errors.push(errorItem);
this.formErrors.push(errorItem);
}
//
if (col.bodySubKey&& !col.bodySubDisabled) {
const subValue = row[col.bodySubKey];
console.log(col,subValue,"subValue")
if (this.isValueEmpty(subValue)) {
errors.push({
const errorItem = {
rowIndex,
colIndex,
field: col.bodySubKey,
label: `${col.label}单位`,
error: `请填写${col.label}单位`
});
};
errors.push(errorItem);
this.formErrors.push(errorItem);
}
}
}
@ -236,12 +243,24 @@ export default {
onBodyValueChange(rowIndex, colIndex, value) {
const col = this.columns[colIndex];
this.localDataSource[rowIndex][col.prop] = value;
//
this.formErrors = this.formErrors.filter(error =>
!(error.rowIndex === rowIndex &&
error.colIndex === colIndex &&
error.field === col.prop)
);
this.$emit('body-value-change', rowIndex, colIndex, value);
},
//
onBodySubValueChange(rowIndex, colIndex, value) {
const col = this.columns[colIndex];
this.localDataSource[rowIndex][col.bodySubKey] = value;
//
this.formErrors = this.formErrors.filter(error =>
!(error.rowIndex === rowIndex &&
error.colIndex === colIndex &&
error.field === col.bodySubKey)
);
this.$emit('body-sub-value-change', rowIndex, colIndex, value);
},
getHeaderItem(col) {
@ -303,6 +322,24 @@ export default {
console.log(this.localDataSource,"this.localDataSource")
this.localDataSource = [...this.localDataSource];
},
//
hasError(rowIndex, colIndex, field) {
return this.formErrors.some(error =>
error.rowIndex === rowIndex &&
error.colIndex === colIndex &&
error.field === field
);
},
//
onErrorUpdate(rowIndex, colIndex, field, isError) {
if (!isError) {
this.formErrors = this.formErrors.filter(error =>
!(error.rowIndex === rowIndex &&
error.colIndex === colIndex &&
error.field === field)
);
}
},
onSubBlur(rowIndex, colKey, value) {
this.$emit("blur", {rowIndex, colKey, value,item:this.localDataSource[rowIndex]});
},

+ 15
- 3
src/components/Template/DecimalInput.vue View File

@ -18,7 +18,7 @@ export default {
},
decimalDigits: {
type: Number,
default: 3
default: 6
},
placeholder: {
type: String,
@ -136,8 +136,20 @@ export default {
return;
}
// blur toFixed +
const formatted = num.toFixed(this.decimalDigits);
//
let formatted = String(num);
//
if (!finalValue.includes('.')) {
formatted = String(Math.floor(num));
} else {
//
const decPart = finalValue.split('.')[1];
const actualDecimalDigits = decPart.length;
const displayDecimalDigits = Math.min(actualDecimalDigits, this.decimalDigits);
formatted = num.toFixed(displayDecimalDigits).replace(/\.?0*$/, '');
}
this.internalValue = formatted;
// emit emit
this.$emit('input', parseFloat(formatted));

+ 75
- 6
src/components/Template/HandleFormItem.vue View File

@ -3,32 +3,32 @@
<div class="flex1 flex">
<el-input v-if="type === 'input'" :maxlength="item.maxlength || 50" :disabled="getDisabled()"
:class="getFillTypeStyle()" @blur="onBlur"
:placeholder="item.placeholder ? item.placeholder : ('请输入' + item.label)" v-model="inputValue"
:placeholder="getPlaceholder()" v-model="inputValue"
@input="onInputChange" @change="onInputChange" />
<el-input v-else-if="type === 'textarea'" :maxlength="item.maxlength || 50" :disabled="getDisabled()"
:class="getFillTypeStyle()" type="textarea" show-word-limit resize="none" @blur="onBlur"
:rows="item.rows || 3" :placeholder="item.placeholder ? item.placeholder : ('请输入' + item.label)"
:rows="item.rows || 3" :placeholder="getPlaceholder()"
v-model="inputValue" @input="onInputChange" @change="onInputChange" />
<DecimalInput v-else-if="type === 'inputNumber'" @blur="onBlur" :maxlength="item.maxlength || 10"
class="flex1" :disabled="getDisabled()" :controls="item.controls || false" :min="item.min || 0"
:prepend = "item.prepend"
:decimalDigits="item.precision" :class="getFillTypeStyle()"
:placeholder="item.placeholder ? item.placeholder : ('请输入' + item.label)" v-model="inputValue"
:placeholder="getPlaceholder()" v-model="inputValue"
@input="onInputChange" @change="onInputChange" />
<el-select v-else-if="type === 'select'" class="flex1" :multiple="item.multiple"
:class="getFillTypeStyle()" v-model="inputValue" :disabled="getDisabled()"
:placeholder="item.placeholder ? item.placeholder : ('请选择' + item.label)" @change="onInputChange">
:placeholder="getPlaceholder()" @change="onInputChange">
<el-option v-for="op in item.options" :key="op.value" :label="op.label" :value="op.value">
</el-option>
</el-select>
<el-date-picker v-else-if="type === 'dateTime'" type="datetime" class="flex1" :class="getFillTypeStyle()"
v-model="inputValue" :disabled="getDisabled()" format="yyyy/MM/DD HH:mm:ss"
value-format="yyyy/MM/DD HH:mm:ss"
:placeholder="item.placeholder ? item.placeholder : ('请选择' + item.label)" @change="onInputChange">
:placeholder="getPlaceholder()" @change="onInputChange">
</el-date-picker>
<div class="clickable" :class="getFillTypeStyle() + (getDisabled()?' disabled':'')" v-else-if = "item.type ==='clickable'" @click="handleClickable(item,$event)">
<span v-if="value">{{ value }}</span>
<span v-else class="default-placeholder-text">请选择</span>
<span v-else class="default-placeholder-text">{{getPlaceholder()}}</span>
</div>
</div>
<!-- qc才能操作 -->
@ -71,6 +71,11 @@ export default {
type: [String, Number, Array],
default: ''
},
//
error: {
type: Boolean,
default: false
},
},
data() {
return {
@ -94,6 +99,10 @@ export default {
green: "green-border",
preFill: "blue-border",//
}
//
if (this.error) {
return "error-border";
}
return typeObj[fillType] || ""
},
//question
@ -106,6 +115,10 @@ export default {
const value = val !== undefined ? val : this.inputValue;
this.$emit('input', value);
this.$emit('change', value);
//
if (this.error) {
this.$emit('update:error', false);
}
},
handleClickable(item,event){
if(item.fillType !== 'actFill'){
@ -143,10 +156,30 @@ export default {
}
}
},
getPlaceholder() {
const { placeholder,label } = this.item;
const {type} = this;
if(this.getDisabled()){
return ""
}
if(type === "clickable"){
return "请选择"
}
let prex = "请输入";
if(type === "select" || type === "dateTime"){
prex = "请选择"
}
return placeholder ? placeholder : (prex + label)
},
onCopy() {
this.$emit("copy")
},
onBlur(val) {
//
if (this.error) {
this.$emit('update:error', false);
}
this.$emit("blur", val)
},
},
@ -258,6 +291,42 @@ export default {
}
}
.error-border {
.el-input-group__prepend,input,
textarea,
.el-select,
.el-date-editor {
border-color: #f56c6c;
&:focus {
border-color: #f56c6c;
}
&:hover {
border-color: #f56c6c;
}
}
// el-select el-date-picker
.el-select .el-input__inner,
.el-date-editor .el-input__inner {
border-color: #f56c6c;
}
// DecimalInput
:deep(.el-input-number) {
.el-input__inner {
border-color: #f56c6c;
}
}
//
.clickable {
border-color: #f56c6c;
}
}
.clickable{
cursor: pointer;
width: auto;

+ 2
- 2
vue.config.js View File

@ -34,8 +34,8 @@ module.exports = {
proxy: {
// detail: https://cli.vuejs.org/config/#devserver-proxy
[process.env.VUE_APP_BASE_API]: {
target: `http://localhost:8080`,
// target: `http://39.99.251.173:8080`,
// target: `http://localhost:8080`,
target: `http://39.99.251.173:8080`,
changeOrigin: true,
pathRewrite: {
['^' + process.env.VUE_APP_BASE_API]: ''

Loading…
Cancel
Save