github.com/easysoft/zendata@v0.0.0-20240513203326-705bd5a7fd67/ui/src/components/FieldRange.vue (about) 1 <template> 2 <div class="panel"> 3 <a-form-model ref="editForm"> 4 <a-row :gutter="cols" class="title"> 5 <a-col :span="col">{{ $t('form.type') }}</a-col> 6 <a-col :span="col">{{ $t('form.value') }}</a-col> 7 <a-col :span="col">{{ $t('form.opt') }}</a-col> 8 </a-row> 9 10 <a-row v-if="!sections || sections.length == 0" :gutter="cols"> 11 <a-col :span="col"></a-col> 12 <a-col :span="col"></a-col> 13 <a-col :span="col"> 14 <a class="edit"> 15 <a @click="insertSection()" class="edit">{{ $t('action.add') }}</a> 16 </a> 17 </a-col> 18 </a-row> 19 20 <a-row v-for="item in sections" :key="item.id" :gutter="cols"> 21 22 <a-col :span="col"> 23 <span v-if="item.type=='interval'">{{ $t('form.type.interval') }}</span> 24 <span v-if="item.type=='list'">{{ $t('form.type.list') }}</span> 25 <span v-if="item.type=='literal'">{{ $t('form.type.literal') }}</span> 26 </a-col> 27 28 <a-col :span="col"> 29 <span>{{ item.value }}</span> 30 </a-col> 31 32 <a-col :span="8"> 33 <a class="edit"> 34 <a @click="insertSection(item)" class="edit">{{ $t('action.add') }}</a> 35 <a @click="editSection(item)" class="edit">{{ $t('action.edit') }}</a> 36 <a-popconfirm 37 :title="$t('tips.delete')" 38 :okText="$t('msg.yes')" 39 :cancelText="$t('msg.no')" 40 @confirm="removeSection(item)" 41 > 42 <a class="edit">{{ $t('action.delete') }}</a> 43 </a-popconfirm> 44 </a> 45 </a-col> 46 </a-row> 47 </a-form-model> 48 49 <a-modal 50 :title="editTitle" 51 :width="600" 52 :visible="editSectionVisible" 53 :okText="$t('form.save')" 54 :cancelText="$t('form.cancel')" 55 @ok="saveSection" 56 @cancel="cancelSection"> 57 <div> 58 <a-form-model ref="editForm" :model="section" :rules="rules"> 59 60 <a-row :gutter="cols"> 61 <a-col :span="cols"> 62 <a-form-model-item :label="$t('form.type')" prop="type" :labelCol="labelColFull" :wrapperCol="wrapperColFull"> 63 <a-select v-model="section.type"> 64 <a-select-option value="interval">{{ $t('form.type.interval') }}</a-select-option> 65 <a-select-option value="list">{{ $t('form.type.list') }}</a-select-option> 66 <a-select-option value="literal">{{ $t('form.type.literal') }}</a-select-option> 67 </a-select> 68 </a-form-model-item> 69 </a-col> 70 </a-row> 71 72 <div v-if="section.type==='interval'"> 73 <a-row :gutter="cols"> 74 <a-col :span="cols"> 75 <a-form-model-item :label="$t('form.start')" prop="start" :labelCol="labelColFull" :wrapperCol="wrapperColFull"> 76 <a-input v-model="section.start" :placeholder="$t('tips.number.or.letter')" /> 77 </a-form-model-item> 78 </a-col> 79 </a-row> 80 <a-row :gutter="cols"> 81 <a-col :span="cols"> 82 <a-form-model-item :label="$t('form.end')" prop="end" :labelCol="labelColFull" :wrapperCol="wrapperColFull"> 83 <a-input v-model="section.end" :placeholder="$t('tips.number.or.letter')" /> 84 </a-form-model-item> 85 </a-col> 86 </a-row> 87 <a-row :gutter="cols"> 88 <a-col :span="cols"> 89 <a-form-model-item :label="$t('form.repeat')" prop="repeat" :labelCol="labelColFull" :wrapperCol="wrapperColFull"> 90 <a-input v-model="section.repeat" :precision="0" :min="1" placeholder="" /> 91 </a-form-model-item> 92 </a-col> 93 </a-row> 94 <a-row :gutter="cols"> 95 <a-col :span="cols"> 96 <a-form-model-item :label="$t('form.repeatTag')" prop="repeatTag" :labelCol="labelColFull" :wrapperCol="wrapperColFull"> 97 <a-radio-group v-model="section.repeatTag"> 98 <a-radio :value="''"> 99 {{ $t('form.repeatItem') }} 100 </a-radio> 101 <a-radio :value="'!'"> 102 {{ $t('form.repeatGroup') }} 103 </a-radio> 104 </a-radio-group> 105 </a-form-model-item> 106 </a-col> 107 </a-row> 108 109 <a-row :gutter="cols"> 110 <a-col :span="cols"> 111 <a-form-model-item :label="$t('form.rand')" prop="rand" :labelCol="labelColFull" :wrapperCol="wrapperColFull"> 112 <a-switch v-model="section.rand" /> 113 </a-form-model-item> 114 </a-col> 115 </a-row> 116 <a-row :gutter="cols" v-if="!section.rand"> 117 <a-col :span="cols"> 118 <a-form-model-item :label="$t('form.step')" prop="step" :labelCol="labelColFull" :wrapperCol="wrapperColFull"> 119 <a-input v-model="section.step" :placeholder="$t('tips.number')" /> 120 </a-form-model-item> 121 </a-col> 122 </a-row> 123 </div> 124 125 <div v-if="section.type==='list'"> 126 <a-row :gutter="cols"> 127 <a-col :span="cols"> 128 <a-form-model-item :label="$t('form.type.list')" prop="text" :labelCol="labelColFull" :wrapperCol="wrapperColFull"> 129 <a-input v-model="section.text" type="textarea" rows="3" /> 130 {{$t('tips.value.each.line')}} 131 </a-form-model-item> 132 </a-col> 133 </a-row> 134 </div> 135 136 <div v-if="section.type==='literal'"> 137 <a-row :gutter="cols"> 138 <a-col :span="cols"> 139 <a-form-model-item label="常量" prop="text" :labelCol="labelColFull" :wrapperCol="wrapperColFull"> 140 <a-input v-model="section.text" placeholder="" /> 141 </a-form-model-item> 142 </a-col> 143 </a-row> 144 </div> 145 </a-form-model> 146 147 </div> 148 149 </a-modal> 150 151 </div> 152 </template> 153 154 <script> 155 import { 156 listSection, createSection, removeSection, updateSection, 157 } from "../api/section"; 158 import {sectionStrToArr, trimChar} from "../api/utils"; 159 160 export default { 161 name: 'FieldRangeComponent', 162 data() { 163 return { 164 cols: 24, 165 colsHalf: 12, 166 col: 8, 167 labelColFull: { lg: { span: 4 }, sm: { span: 4 } }, 168 labelColHalf: { lg: { span: 8}, sm: { span: 8 } }, 169 wrapperColFull: { lg: { span: 16 }, sm: { span: 16 } }, 170 wrapperColHalf: { lg: { span: 12 }, sm: { span: 12 } }, 171 172 sections: [], 173 section: {}, 174 editTitle: '', 175 editSectionVisible: false, 176 177 rules: { 178 type: [ 179 { required: true, message: this.$i18n.t('valid.type.empty'), trigger: 'change' }, 180 ], 181 start: [ 182 { required: true, message: this.$i18n.t('valid.number.or.single.letter'), trigger: 'change' }, 183 { validator: this.checkRange, trigger: 'change' }, 184 ], 185 end: [ 186 { required: true, message: this.$i18n.t('valid.number.or.single.letter'), trigger: 'change' }, 187 { validator: this.checkRange, trigger: 'change' }, 188 ], 189 repeat: [ 190 { validator: this.checkRepeat, message: this.$i18n.t('valid.unsigned.integer'), trigger: 'change' }, 191 ], 192 step: [ 193 { validator: this.checkStep, message: this.$i18n.t('valid.number'), trigger: 'change' }, 194 ], 195 }, 196 }; 197 }, 198 props: { 199 type: { 200 type: String, 201 default: () => '' 202 }, 203 model: { 204 type: Object, 205 default: () => null 206 }, 207 time2: { 208 type: Number, 209 default: () => 0 210 }, 211 }, 212 213 computed: { 214 }, 215 created () { 216 console.log('created') 217 218 this.loadData() 219 this.$watch('time2', () => { 220 console.log('time2 changed', this.time2) 221 this.loadData() 222 }) 223 }, 224 mounted () { 225 console.log('mounted') 226 }, 227 methods: { 228 loadData () { 229 console.log('loadData', this.type, this.model) 230 if (!this.model.id) return 231 232 listSection(this.model.id, this.type).then(res => { 233 console.log('listSection', res) 234 this.sections = res.data 235 }) 236 }, 237 insertSection (item) { 238 createSection(this.model.id, item ? item.id : 0, this.type).then(res => { 239 console.log('createSection', res) 240 this.sections = res.data 241 }) 242 }, 243 244 editSection (item) { 245 console.log('editSection', item) 246 247 if (item.type === 'interval') { 248 this.editTitle = '编辑范围' 249 } else if (item.type === 'literal') { 250 this.editTitle = '编辑字面常量' 251 item.text = trimChar(item.value, '`') 252 } else if (item.type === 'list') { 253 this.editTitle = '编辑数组' 254 item.text = item.value 255 item.text = sectionStrToArr(item.value) 256 } 257 258 this.section = item 259 this.editSectionVisible = true 260 }, 261 saveSection() { 262 this.$refs.editForm.validate(valid => { 263 console.log(valid, this.section) 264 if (!valid) { 265 console.log('validation fail') 266 return 267 } 268 269 if (this.section.type === 'interval') { 270 this.section.value = this.section.start + '-' + this.section.end 271 272 if (this.section.rand) { 273 this.section.value += ':R' 274 this.section.step = 0 275 } else if (this.section.step && this.section.step != '' && this.section.step != 1) { 276 const regx = /^[a-z,A-Z]$/ 277 if (regx.test(this.section.start) || regx.test(this.section.end)) { 278 this.section.step = Math.floor(this.section.step) 279 } 280 281 this.section.value += ':' + this.section.step 282 } 283 284 if (this.section.repeat && this.section.repeat != '' && this.section.repeat != '1') { 285 this.section.value += '{' + this.section.repeat + this.section.repeatTag + '}' 286 } 287 288 } else if (this.section.type === 'literal') { 289 this.section.value = '`' + this.section.text + '`' 290 291 } else if (this.section.type === 'list') { 292 const arr = this.section.text.split('\n') 293 this.section.value = '[' + arr.join(',') + ']' 294 } 295 296 this.section.step = parseInt(this.section.step) 297 updateSection(this.section, this.type).then(res => { 298 console.log('updateSection', res) 299 this.sections = res.data 300 }) 301 302 this.editSectionVisible = false 303 }) 304 }, 305 cancelSection() { 306 console.log('cancelSection') 307 this.editSectionVisible = false 308 }, 309 310 removeSection (item) { 311 console.log(item) 312 removeSection(item.id, this.type).then(res => { 313 console.log('removeSection', res) 314 this.sections = res.data 315 }) 316 }, 317 checkRange (rule, value, callback){ 318 console.log('checkRange', value) 319 320 const test1 = /^[0-9]+\.?[0-9]*$/.test(value); 321 const test2 = /^[a-z,A-Z]$/.test(value); 322 if (!test1 && !test2) { 323 callback('必须是数字或单个字母') 324 } 325 326 callback() 327 }, 328 checkRepeat(rule, value, callback) { 329 const test = /^[1-9][0-9]*$/.test(value); 330 if (!test) { 331 callback('必须是正整数') 332 } 333 callback() 334 }, 335 checkStep(rule, value, callback) { 336 const test = /^[0-9]+\.?[0-9]*$/.test(value); 337 if (!test) { 338 callback('必须是数字') 339 } 340 callback() 341 } 342 } 343 } 344 </script> 345 346 <style lang="less" scoped> 347 .panel { 348 padding: 4px 8px; 349 .title { 350 font-weight: bolder; 351 margin-bottom: 5px; 352 padding-bottom: 5px; 353 border-bottom: 1px solid #e9f2fb; 354 } 355 .radios { 356 margin-bottom: 12px; 357 .range { 358 display: inline-block; 359 margin-left: 12px; 360 } 361 } 362 .edit { 363 line-height: 32px; 364 } 365 } 366 </style>