We read every piece of feedback, and take your input very seriously.
To see all available qualifiers, see our documentation.
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
落笔前,先期望疫情快快过去,都要生锈了都~
模拟接口请求,对请求头的参数进行处理,如下图:
嗯,我是用的vue版本的ant design,然后实现之后是这样的:
vue
ant design
相关代码:
<template> <div class="mock-info"> <a-form :form="form"> <!-- 基本信息 --> <a-divider orientation="left" style="color: #1890ff;">基本信息</a-divider> <a-form-item v-bind="formItemLayout" label="期待名称"> <a-input v-decorator="[ 'name', {rules: [{ required: true, message: '请输入环境域名'}]} ]" placeholder="请输入期待名称"/> </a-form-item> <a-form-item style="margin-bottom: 0;" v-bind="formItemLayoutWithOutLabel"> <a-switch checkedChildren="JSON" unCheckedChildren="JSON" v-decorator="['is_json', {valuePropName: 'checked', initialValue: false }]" /> </a-form-item> <div class="paramsArr" v-show="!form.getFieldValue('is_json')"> <!--非json展示输入框--> <a-form-item v-for="(k, index) in form.getFieldValue('baseKeys')" :key="k" v-bind="index === 0 ? formItemLayout : formItemLayoutWithOutLabel" :label="index === 0 ? '参数名称' : ''" :required="false" style="margin-bottom: 0;"> <a-input v-decorator="[`paramNames[${k}]`]" placeholder="参数过滤" style="width: 40%; margin-right: 8px"/> <a-input v-decorator="[`paramValues[${k}]`]" placeholder="参数值" style="width: 40%; margin-right: 8px"/> <a-icon v-if="form.getFieldValue('baseKeys').length > 1" class="dynamic-delete-button" type="minus-circle-o" :disabled="form.getFieldValue('baseKeys').length === 1" @click="() => removeParam(k)"/> </a-form-item> <a-form-item v-bind="formItemLayoutWithOutLabel"> <a-button type="primary" style="width: 60%" @click="addParam"> <a-icon type="plus" /> 添加参数 </a-button> </a-form-item> </div> <div v-show="form.getFieldValue('is_json')"> <a-form-item v-bind="formItemLayout" label="参数名称"> <v-jsoneditor style="margin-top: 12px;" :options="options" v-model="request_params" /> </a-form-item> </div> <!-- 响应信息 --> <a-divider orientation="left" style="color: #1890ff;">响应</a-divider> <a-form-item v-bind="formItemLayout" label="HTTP Code"> <a-select v-decorator="[ 'http_code', {rules: [{ required: false, message: '请选择'}]} ]" showSearch placeholder="请选择"> <a-select-option v-for="(item, index) in codes" :key="index" :value="item">{{item}}</a-select-option> </a-select> </a-form-item> <a-form-item v-bind="formItemLayout" label="延时"> <a-input-number v-decorator="['delay_time', { initialValue: 0 }]" :min="0"/> ms </a-form-item> <div class="httpArr"> <a-form-item v-for="(k, index) in form.getFieldValue('httpKeys')" :key="k" v-bind="index === 0 ? formItemLayout : formItemLayoutWithOutLabel" :label="index === 0 ? 'HTTP头' : ''" :required="false" style="margin-bottom: 0;"> <a-select mode="combobox" v-decorator="[`httpNames[${k}]`]" showSearch placeholder="请选择" style="width: 40%; margin-right: 8px"> <a-select-option v-for="(item, index) in http_headers" :key="index" :value="item">{{item}}</a-select-option> </a-select> <a-input v-decorator="[`httpValues[${k}]`]" placeholder="参数值" style="width: 40%; margin-right: 8px"/> <a-icon v-if="form.getFieldValue('httpKeys').length > 1" class="dynamic-delete-button" type="minus-circle-o" :disabled="form.getFieldValue('httpKeys').length === 1" @click="() => removeHttp(k)"/> </a-form-item> <a-form-item v-bind="formItemLayoutWithOutLabel"> <a-button type="primary" style="width: 60%" @click="addHttp"> <a-icon type="plus" /> 添加HTTP头 </a-button> </a-form-item> </div> <a-form-item v-bind="formItemLayout" label="Body"> <v-jsoneditor style="margin-top: 12px;" :options="options" v-model="response_body" /> </a-form-item> </a-form> </div> </template>
<script> import VJsoneditor from 'v-jsoneditor' export default { name: 'mock-info', components: { VJsoneditor, // json编辑器 }, props: { row: Object, // 回填信息 }, data() { const formItemLayout = { labelCol: { span: 5 }, wrapperCol: { span: 18 }, }; const formItemLayoutWithOutLabel = { wrapperCol: { span: 18, offset: 5 }, }; const options = { mainMenuBar: false, mode: 'code' }; // 可以考虑后端返回,也允许用户自己添加 const codes = [100, 101, 102, 200, 201, 202, 203, 204, 205, 206, 207, 208, 226, 300, 301, 302, 303, 304, 305, 307, 308, 400, 401, 402, 403, 404, 405, 406, 407, 408, 409, 410, 411, 412, 413, 414, 415, 416, 417, 418, 422, 423, 424, 426, 428, 429, 431, 500, 501, 502, 503, 504, 505, 506, 507, 508, 510, 511] // 可以考虑后端返回,也允许用户自己添加 const http_headers = ['Accept', 'Accept-Charset', 'Accept-Encoding', 'Accept-Language', 'Accept-Datetime', 'Authorization', 'Cache-Control', 'Connection', 'Cookie', 'Content-Disposition', 'Content-Length', 'Content-MD5', 'Content-Type', 'Date', 'Expect', 'From', 'Host', 'If-Match', 'If-Modified-Since', 'If-None-Match', 'If-Range', 'If-Unmodified-Since', 'Max-Forwards', 'Origin', 'Pragma', 'Proxy-Authorization', 'Range', 'Referer', 'TE', 'User-Agent', 'Upgrade', 'Via', 'Warning', 'X-Requested-With', 'DNT', 'X-Forwarded-For', 'X-Forwarded-Host', 'X-Forwarded-Proto', 'Front-End-Https', 'X-Http-Method-Override', 'X-ATT-DeviceId', 'X-Wap-Profile', 'Proxy-Connection', 'X-UIDH', 'X-Csrf-Token'] return { formItemLayout, formItemLayoutWithOutLabel, options, baseId: 0, // 基本信息的ID httpId: 0, // 响应信息得ID request_params: {}, // 请求参数 response_body: {}, // 响应参数 codes, http_headers, itemVal: '' }; }, beforeCreate() { // 创建form this.form = this.$form.createForm(this, { name: 'form' }); this.form.getFieldDecorator('baseKeys', { initialValue: [0], preserve: true }); this.form.getFieldDecorator('httpKeys', { initialValue: [0], preserve: true }); }, mounted() { let vm = this // 信息回填 vm.form.setFieldsValue({ name: vm.row.name, is_json: vm.row.is_json == '1' ? true : false, // 这里考虑'0','1','2'之类的 http_code: vm.row.resp_code, delay_time: vm.row.delay || 0 }) if(vm.row.id) { vm.response_body = JSON.parse(vm.row.resp_body) vm.form.id = vm.row.id // 回填请求参数 if(vm.row.is_json == '0') { // 非JSON vm.rollbackKeyValue(JSON.parse(vm.row.request_params), 'paramNames', 'paramValues', 'baseKeys', 'baseId') } if(vm.row.is_json == '1') { // JSON格式 vm.request_params = JSON.parse(vm.row.request_params) } // 回填响应参数 vm.rollbackKeyValue(JSON.parse(vm.row.resp_header), 'httpNames', 'httpValues', 'httpKeys', 'httpId') } }, methods: { // 回填keyValues值 rollbackKeyValue(objectData, names, values, keys, seq) { let vm = this let temp_names = [], temp_values = [], temp_keys = []; let objKeys = Object.keys(objectData) if(objKeys.length > 0) { objKeys.map((name, index) => { temp_names.push(name) temp_values.push(objectData[name]) temp_keys.push(index) vm[seq] = index }) // 回填 vm.form.setFieldsValue({ [keys]: temp_keys, // 这个要先出来,保证UI被渲染出来了 }) vm.$nextTick(() => { // nextTick保证dom被渲染好之后进行下一步操作 vm.form.setFieldsValue({ [names]: temp_names, [values]: temp_values }) }) } }, // 移除参数 removeParam(k) { const { form } = this; const baseKeys = form.getFieldValue('baseKeys'); if (baseKeys.length === 1) { return; } form.setFieldsValue({ baseKeys: baseKeys.filter(key => key !== k), }); }, // 移除http removeHttp(k) { const { form } = this; const httpKeys = form.getFieldValue('httpKeys'); if (httpKeys.length === 1) { return; } form.setFieldsValue({ httpKeys: httpKeys.filter(key => key !== k), }); }, // 添加参数 addParam() { const { form } = this; const baseKeys = form.getFieldValue('baseKeys'); const nextKeys = baseKeys.concat(++this.baseId); form.setFieldsValue({ baseKeys: nextKeys, }); }, // 添加Http addHttp() { const { form } = this; const httpKeys = form.getFieldValue('httpKeys'); const nextKeys = httpKeys.concat(++this.httpId); form.setFieldsValue({ httpKeys: nextKeys, }); } }, }; </script>
<style lang="less"> .mock-info { .dynamic-delete-button { cursor: pointer; position: relative; top: 4px; font-size: 24px; color: #999; transition: all 0.3s; } .dynamic-delete-button:hover { color: #777; } .dynamic-delete-button[disabled] { cursor: not-allowed; opacity: 0.5; } } </style>
嗯~这种实现的方式还是和舒服的,不用自己布局,不用自己再次思考逻辑;如果你想自己捣鼓一个,那你是真的闲,还不如花点时间捣鼓其他非编程的东西。
注意:能用react版本的ant design尽量用react版本的~
根据后台接口返回的字段来渲染。类型值对应不同的组件,如下:
类型值1:单行文本组件
类型值2:多行文本组件
类型值3:单选组件
类型值4:多选组件
类型值5:文件上传组件
每种类型出现的次数是大于等于0,而且后端可配置必填或者非必填。嗯,下面实现它~
因为是移动端的业务,肯定是选UI框架帮我干活啊,这里我选了有赞的vant。用的还是vue去搭建工程,别问为啥不用react,公司给我时间,我就用react这是业务线啊,想得倒是美,而且还是疫情期间,不压你时间就很好了。所以做完后,乖乖申请回去中台
vant
react
下面实现的思路,效果和关键代码~
uuid
<!-- 进行字段的遍历 --> <div v-for="(type, type_index) in alterFields"> <!-- 单行文本和多行文本区域 --> <div class="advertise part" v-if="type.fieldType===1 || type.fieldType ===2"> <!-- 单行文本内容 --> <!-- 多行文本内容 --> </div> <!-- 单选和多选区域 --> <div class="advertise part" v-if="type.fieldType===3 || type.fieldType ===4"> <!-- 单选内容 --> <!-- 多选内容 --> </div> <!-- 资源上传的区域 --> <div class="advertise part" v-if="type.fieldType===5"> <!--文件上传内容--> </div> </div>
我这里前端写死了,蓝瘦香菇,三个字"人真懒"。
types: [{ code: 1, text: '单行文本' }, { code: 2, text: '多行文本' }, { code: 3, text: '单选' }, { code: 4, text: '多选' }, { code: 5, text: '文件上传' }],
// 将返回的字段和编辑的字段进行配对,回填 let _alterFields = [] for (let i = 0; i < vm.alterFields.length; i++) { let _item = vm.alterFields[i] _alterFields.push(_item) for (let j = 0; j < vm.editFileds.length; j++) { if (_item.id === vm.editFileds[i].id) { // 替换值 _alterFields.splice(i, 1, Object.assign(_item, { fieldValue: vm.editFileds[i].fieldValue, [_item.uuid]: vm.editFileds[i].fieldValue, })) } } } vm.alterFields = _alterFields
// 文件资源的限制 prompt_for_oversize () { this.$dialog({ title: '提 示', text: '单个文件大小不应该大于10M', confirmText: '了解', showCancelBtn: false, confirm () { } }) }
async await
realUploadFile (item) { let vm = this let temp_valueFiled = [] let be_upload = false return new Promise(resolve => { // 上传到云 let formData = new FormData(); for (let i = 0; i < item[item.uuid].length; i++) { let row = item[item.uuid][i] if (row.fileName) { // 编辑的时候存在文件就不用再上传到服务器了 temp_valueFiled.push(row) if (temp_valueFiled.length === item[item.uuid].length) { resolve(temp_valueFiled) } } else { be_upload = true console.log('row.file', row.file.size) formData.append("files", row.file); } } if (!be_upload) { // 不需要上传的时候直接返回 return } vm.api.apply.uploadMultiFiles(formData).then(res => { console.log(res) if (res.code === '00000') { temp_valueFiled.push(...res.data) resolve(temp_valueFiled) } else { vm.$toast({ msg: res.message || '上传失败,请重试!' }) vm.forbidden = false } }) }) }
// 处理单选框(如果是非必填字段,允许用户取消) handleRadio (type, type_index, item_title) { // type是整个项目,type_index是类型遍历的索引, item_title是选中项目的名称 if (type.isRequired) { return } // 必选的单选框,啥都不做 let vm = this let union = `${type['uuid']}_${item_title}` // 唯一的标识 if (vm.radioSet.has(union)) { // 存在集合中 vm.radioSet.delete(union) vm.alterFields.splice(type_index, 1, Object.assign(type, { [type.uuid]: '' })) } else { if (vm.radioSet.size > 0) { vm.radioSet.forEach(function (val) { if (val.indexOf(`${type['uuid']}_`) >= 0) { vm.radioSet.delete(val) // 移除当前组件的唯一标识的所有值 } }) } vm.radioSet.add(union) // 每个单选的组件只维护一个数据 } },
...
效果如下:
公司业务,我怂,不敢放全部代码
谢谢各位看官的捧场~
The text was updated successfully, but these errors were encountered:
No branches or pull requests
落笔前,先期望疫情快快过去,都要生锈了都~
场景一
模拟接口请求,对请求头的参数进行处理,如下图:
嗯,我是用的
vue
版本的ant design
,然后实现之后是这样的:相关代码:
嗯~这种实现的方式还是和舒服的,不用自己布局,不用自己再次思考逻辑;如果你想自己捣鼓一个,那你是真的闲,还不如花点时间捣鼓其他非编程的东西。
场景二
根据后台接口返回的字段来渲染。类型值对应不同的组件,如下:
类型值1:单行文本组件
类型值2:多行文本组件
类型值3:单选组件
类型值4:多选组件
类型值5:文件上传组件
每种类型出现的次数是大于等于0,而且后端可配置必填或者非必填。嗯,下面实现它~
因为是移动端的业务,肯定是选UI框架帮我干活啊,这里我选了有赞的
vant
。用的还是vue
去搭建工程,别问为啥不用react
,公司给我时间,我就用react
这是业务线啊,想得倒是美,而且还是疫情期间,不压你时间就很好了。所以做完后,乖乖申请回去中台下面实现的思路,效果和关键代码~
uuid
(能叫得动后端,就叫后端配吧...)我这里前端写死了,蓝瘦香菇,三个字"人真懒"。
async await
来操作,更加直观明了...
效果如下:
后话
谢谢各位看官的捧场~
The text was updated successfully, but these errors were encountered: