@@ -12,9 +12,9 @@ ENV = 'development' | |||
VUE_APP_TITLE = 产线监控系统 | |||
# 芋道管理系统/开发环境 | |||
# VUE_APP_BASE_API = 'http://192.168.1.49:48080' | |||
VUE_APP_BASE_API = 'http://192.168.1.49:48080' | |||
# VUE_APP_BASE_API = 'http://192.168.1.8:48080' | |||
VUE_APP_BASE_API = 'http://192.168.0.33:48080' | |||
# VUE_APP_BASE_API = 'http://192.168.0.33:48080' | |||
# VUE_APP_BASE_API = 'http://192.168.1.188:48080' | |||
# 路由懒加载 | |||
@@ -0,0 +1,55 @@ | |||
<!-- | |||
filename: AssetsUpload.vue | |||
author: liubin | |||
date: 2023-10-12 16:40:14 | |||
description: 上传资料/图片 组件 | |||
--> | |||
<template> | |||
<div class="assets-upload"> | |||
asset upload | |||
</div> | |||
</template> | |||
<script> | |||
export default { | |||
name: 'AssetsUpload', | |||
components: {}, | |||
props: { | |||
type: { | |||
type: String, | |||
default: 'image', | |||
}, | |||
dataSource: { | |||
type: Array, | |||
default: () => [], | |||
}, | |||
equipmentId: { | |||
type: String, | |||
default: '', | |||
}, | |||
}, | |||
emits: ['update-filelist'], | |||
data() { | |||
return { | |||
fileList: [], | |||
}; | |||
}, | |||
computed: {}, | |||
methods: { | |||
handleUpload() { | |||
switch (this.type) { | |||
case 'image': | |||
break; | |||
case 'asset': | |||
break; | |||
} | |||
}, | |||
updateFileList(appendFilelist) { // Array | |||
this.$emit('update-filelist', this.appendFilelist); | |||
}, | |||
}, | |||
}; | |||
</script> | |||
<style scoped lang="scss"></style> |
@@ -0,0 +1,312 @@ | |||
<!-- | |||
filename: dialogForm.vue | |||
author: liubin | |||
date: 2023-08-15 10:32:36 | |||
description: 弹窗的表单组件 | |||
--> | |||
<template> | |||
<el-form | |||
ref="form" | |||
:model="form" | |||
:label-width="`${labelWidth}px`" | |||
:size="size" | |||
:label-position="labelPosition" | |||
v-loading="formLoading"> | |||
<el-row :gutter="20" v-for="(row, rindex) in rows" :key="rindex"> | |||
<el-col v-for="col in row" :key="col.label" :span="24 / row.length"> | |||
<el-form-item :label="col.label" :prop="col.prop" :rules="col.rules"> | |||
<el-input | |||
v-if="col.input" | |||
v-model="form[col.prop]" | |||
@change="$emit('update', form)" | |||
:placeholder="`请输入${col.label}`" | |||
v-bind="col.bind" /> | |||
<el-input | |||
v-if="col.textarea" | |||
type="textarea" | |||
v-model="form[col.prop]" | |||
@change="$emit('update', form)" | |||
:placeholder="`请输入${col.label}`" | |||
v-bind="col.bind" /> | |||
<el-select | |||
v-if="col.select" | |||
v-model="form[col.prop]" | |||
:placeholder="`请选择${col.label}`" | |||
@change="$emit('update', form)" | |||
v-bind="col.bind"> | |||
<el-option | |||
v-for="opt in optionListOf[col.prop]" | |||
:key="opt.value" | |||
:label="opt.label" | |||
:value="opt.value" /> | |||
</el-select> | |||
<el-date-picker | |||
v-if="col.datetime" | |||
v-model="form[col.prop]" | |||
type="datetime" | |||
:placeholder="`请选择${col.label}`" | |||
value-format="timestamp" | |||
v-bind="col.bind"></el-date-picker> | |||
<el-upload | |||
class="upload-in-dialog" | |||
v-if="col.upload" | |||
:file-list="uploadedFileList" | |||
:action="col.url" | |||
:on-success="handleUploadSuccess" | |||
v-bind="col.bind"> | |||
<el-button | |||
size="small" | |||
type="primary" | |||
:disabled="col.bind?.disabled || false"> | |||
点击上传 | |||
</el-button> | |||
<div class="el-upload__tip" slot="tip" v-if="col.uploadTips"> | |||
{{ col.uploadTips || '只能上传jpg/png文件,大小不超过2MB' }} | |||
</div> | |||
</el-upload> | |||
<el-switch | |||
v-if="col.switch" | |||
v-model="form[col.prop]" | |||
active-color="#0b58ff" | |||
inactive-color="#e1e1e1" | |||
v-bind="col.bind"></el-switch> | |||
<component | |||
v-if="col.subcomponent" | |||
:key="col.key" | |||
:is="col.subcomponent" | |||
:inlineStyle="col.style"></component> | |||
</el-form-item> | |||
</el-col> | |||
</el-row> | |||
</el-form> | |||
</template> | |||
<script> | |||
/** | |||
* 找到最长的label | |||
* @param {*} options | |||
*/ | |||
function findMaxLabelWidth(rows) { | |||
let max = 0; | |||
rows.forEach((row) => { | |||
row.forEach((opt) => { | |||
// debugger; | |||
if (!opt.label) return 0; | |||
if (opt.label.length > max) { | |||
max = opt.label.length; | |||
} | |||
}); | |||
}); | |||
return max; | |||
} | |||
export default { | |||
name: 'DialogForm', | |||
model: { | |||
prop: 'dataForm', | |||
event: 'update', | |||
}, | |||
emits: ['update'], | |||
components: {}, | |||
props: { | |||
rows: { | |||
type: Array, | |||
default: () => [], | |||
}, | |||
dataForm: { | |||
type: Object, | |||
default: () => ({}), | |||
}, | |||
disabled: { | |||
type: Boolean, | |||
default: false, | |||
}, | |||
labelPosition: { | |||
type: String, | |||
default: 'right', | |||
}, | |||
size: { | |||
type: String, | |||
default: '', | |||
}, | |||
}, | |||
data() { | |||
return { | |||
formLoading: true, | |||
optionListOf: {}, | |||
uploadedFileList: [], | |||
dataLoaded: false, | |||
}; | |||
}, | |||
computed: { | |||
labelWidth() { | |||
let max = findMaxLabelWidth(this.rows); | |||
// 每个汉字占20px | |||
return max * 20; | |||
// return max * 20 + 'px'; | |||
}, | |||
form: { | |||
get() { | |||
// if (this.dataLoaded) return this.dataForm; | |||
// else return {} | |||
return this.dataForm; | |||
}, | |||
set(val) { | |||
console.log('set form', val); | |||
}, | |||
}, | |||
}, | |||
watch: { | |||
rows: { | |||
handler() { | |||
console.log('watch triggered!'); | |||
this.$nextTick(() => { | |||
this.handleOptions('watch'); | |||
}); | |||
}, | |||
deep: true, | |||
immediate: false, | |||
}, | |||
}, | |||
mounted() { | |||
// 处理 options | |||
this.handleOptions(); | |||
}, | |||
methods: { | |||
/** 模拟透传 ref */ | |||
validate(cb) { | |||
return this.$refs.form.validate(cb); | |||
}, | |||
resetFields(args) { | |||
return this.$refs.form.resetFields(args); | |||
}, | |||
// getCode | |||
async getCode(url) { | |||
const response = await this.$axios(url); | |||
return response.data; | |||
}, | |||
async handleOptions(trigger = 'monuted') { | |||
console.log('[dialogForm:handleOptions]'); | |||
const promiseList = []; | |||
this.rows.forEach((cols) => { | |||
cols.forEach((opt) => { | |||
if (opt.value && !this.form[opt.prop]) { | |||
// 默认值 | |||
this.form[opt.prop] = opt.value; | |||
} | |||
if (opt.options) { | |||
this.$set(this.optionListOf, opt.prop, opt.options); | |||
} else if (opt.url) { | |||
// 如果有 depends,则暂时先不获取,注册一个watcher | |||
if (opt.depends) { | |||
console.log('[handleOptions] setting watch'); | |||
this.$watch( | |||
() => this.form[opt.depends], | |||
(id) => { | |||
console.log('<', opt.depends, '>', 'changed', id); | |||
if (id == null) return; | |||
// 清空原有选项 | |||
this.form[opt.prop] = null; | |||
// 获取新的选项 | |||
this.$axios({ | |||
url: `${opt.url}?id=${id}`, | |||
}).then((res) => { | |||
this.$set( | |||
this.optionListOf, | |||
opt.prop, | |||
res.data.map((item) => ({ | |||
label: item[opt.labelKey ?? 'name'], | |||
value: item[opt.valueKey ?? 'id'], | |||
})) | |||
); | |||
}); | |||
}, | |||
{ | |||
immediate: true, | |||
} | |||
); | |||
return; | |||
} | |||
// 如果是下拉框,或者新增模式下的输入框,才去请求 | |||
if (opt.select || (opt.input && !this.form?.id)) { | |||
promiseList.push(async () => { | |||
const response = await this.$axios(opt.url, { | |||
method: opt.method ?? 'get', | |||
}); | |||
console.log('[dialogForm:handleOptions:response]', response); | |||
if (opt.select) { | |||
// 处理下拉框选项 | |||
const list = | |||
'list' in response.data | |||
? response.data.list | |||
: response.data; | |||
this.$set( | |||
this.optionListOf, | |||
opt.prop, | |||
list.map((item) => ({ | |||
label: item[opt.labelKey ?? 'name'], | |||
value: item[opt.valueKey ?? 'id'], | |||
})) | |||
); | |||
} else if (opt.input) { | |||
console.log('setting code: ', response.data); | |||
// 处理输入框数据 | |||
this.form[opt.prop] = response.data; | |||
} | |||
}); | |||
} | |||
} | |||
}); | |||
}); | |||
console.log('[dialogForm:handleOptions] done!'); | |||
// 如果是 watch 触发的,不需要执行进一步的请求 | |||
if (trigger == 'watch') { | |||
this.formLoading = false; | |||
return; | |||
} | |||
try { | |||
await Promise.all(promiseList.map((fn) => fn())); | |||
this.formLoading = false; | |||
this.dataLoaded = true; | |||
// console.log("[dialogForm:handleOptions:optionListOf]", this.optionListOf) | |||
} catch (error) { | |||
console.log('[dialogForm:handleOptions:error]', error); | |||
this.formLoading = false; | |||
} | |||
if (!promiseList.length) this.formLoading = false; | |||
}, | |||
// 上传成功的特殊处理 | |||
beforeUpload() {}, | |||
// 上传前的验证规则可通过 bind 属性传入 | |||
handleUploadSuccess(response, file, fileList) { | |||
console.log( | |||
'[dialogForm:handleUploadSuccess]', | |||
response, | |||
file, | |||
fileList, | |||
this.form | |||
); | |||
// 保存原始文件名 | |||
if ('fileNames' in this.form) this.form.fileNames.push(file.name); | |||
// 保存完整地址 | |||
if ('fileUrls' in this.form) this.form.fileUrls.push(response.data); | |||
this.$modal.msgSuccess('上传成功'); | |||
}, | |||
getFileName(fileUrl) { | |||
return fileUrl.split('/').pop(); | |||
}, | |||
}, | |||
}; | |||
</script> | |||
<style scoped lang="scss"> | |||
.el-date-editor, | |||
.el-select { | |||
width: 100%; | |||
} | |||
</style> |
@@ -106,7 +106,7 @@ | |||
</template> | |||
<script> | |||
import DialogForm from '@/components/DialogForm'; | |||
import DialogForm from './DialogForm'; | |||
const SmallTitle = { | |||
name: 'SmallTitle', | |||
@@ -45,7 +45,7 @@ | |||
label-position="top" | |||
size="small" | |||
:dataForm="form" | |||
:rows="rows" /> | |||
:rows="computedRows" /> | |||
</base-dialog> | |||
<!-- 设备 详情 - 编辑 --> | |||
@@ -58,7 +58,7 @@ | |||
{ | |||
name: '基本信息', | |||
key: 'base', | |||
rows: rows, | |||
rows: computedRows, | |||
url: '/base/equipment/get', | |||
urlUpdate: '/base/equipment/update', | |||
urlCreate: '/base/equipment/create', | |||
@@ -96,8 +96,8 @@ | |||
}, | |||
]" | |||
@refreshDataList="getList" | |||
@cancel="editVisible = false" | |||
@destroy="editVisible = false" /> | |||
@cancel="cancelEdit" | |||
@destroy="cancelEdit" /> | |||
</div> | |||
</template> | |||
@@ -118,6 +118,7 @@ import { | |||
exportEquipmentExcel, | |||
} from '@/api/base/equipment'; | |||
import Editor from '@/components/Editor'; | |||
import AssetsUpload from './components/AssetsUpload.vue'; | |||
export default { | |||
name: 'Equipment', | |||
@@ -342,40 +343,79 @@ export default { | |||
prop: 'description', | |||
}, | |||
], | |||
[ | |||
{ | |||
upload: true, | |||
label: '上传资料', | |||
prop: 'uploadFiles', | |||
url: process.env.VUE_APP_BASE_API + '/admin-api/infra/file/upload', // 请求地址 | |||
bind: { | |||
headers: { Authorization: 'Bearer ' + getAccessToken() }, | |||
'show-file-list': false, | |||
}, | |||
}, | |||
], | |||
[ | |||
{ | |||
diy: true, | |||
key: 'eq-assets', | |||
label: '设备资料', | |||
prop: 'fileNames', | |||
subcomponent: EquipmentAssets, | |||
}, | |||
], | |||
[ | |||
{ | |||
diy: true, | |||
key: 'eq-pics', | |||
label: '设备图片', | |||
prop: 'fileUrls', | |||
subcomponent: EquipmentPics, | |||
pictures: async () => { | |||
// some async request | |||
return []; | |||
}, | |||
}, | |||
], | |||
// [ | |||
// { | |||
// assetUpload: true, | |||
// label: '上传资料', | |||
// fieldName: 'assets', | |||
// subcomponent: AssetsUpload | |||
// }, | |||
// ], | |||
// [ | |||
// { | |||
// assetUpload: true, | |||
// label: '上传图片', | |||
// fieldName: 'images', | |||
// subcomponent: AssetsUpload | |||
// }, | |||
// ], | |||
// [ | |||
// { | |||
// upload: true, | |||
// label: '上传资料', | |||
// prop: 'uploadFiles', | |||
// url: process.env.VUE_APP_BASE_API + '/admin-api/infra/file/upload', // 请求地址 | |||
// uploadFnName: 'assetsUpload', // 上传方法名 | |||
// bind: { | |||
// headers: { Authorization: 'Bearer ' + getAccessToken() }, | |||
// 'show-file-list': false, | |||
// }, | |||
// }, | |||
// { | |||
// diy: true, | |||
// key: 'eq-assets', | |||
// label: '设备资料', | |||
// prop: 'fileNames', | |||
// subcomponent: EquipmentAssets, | |||
// }, | |||
// ], | |||
// [ | |||
// { | |||
// upload: true, | |||
// label: '上传图片', | |||
// prop: 'uploadImages', | |||
// url: process.env.VUE_APP_BASE_API + '/admin-api/infra/file/upload', // 请求地址 | |||
// uploadFnName: 'imagesUpload', // 上传方法名 | |||
// bind: { | |||
// headers: { Authorization: 'Bearer ' + getAccessToken() }, | |||
// 'show-file-list': false, | |||
// }, | |||
// }, | |||
// { | |||
// diy: true, | |||
// key: 'eq-pics', | |||
// label: '设备图片', | |||
// prop: 'fileUrls', | |||
// subcomponent: EquipmentPics, | |||
// pictures: async () => { | |||
// // some async request | |||
// return []; | |||
// }, | |||
// }, | |||
// ], | |||
// [ | |||
// { | |||
// diy: true, | |||
// key: 'eq-pics', | |||
// label: '设备图片', | |||
// prop: 'fileUrls', | |||
// subcomponent: EquipmentPics, | |||
// pictures: async () => { | |||
// // some async request | |||
// return []; | |||
// }, | |||
// }, | |||
// ], | |||
], | |||
editVisible: false, | |||
editMode: 'edit', // 'edit', 'detail' | |||
@@ -404,11 +444,39 @@ export default { | |||
form: { | |||
id: null, | |||
}, | |||
showUploadComponents: false, // 是否显示上传组件 | |||
}; | |||
}, | |||
created() { | |||
this.getList(); | |||
}, | |||
computed: { | |||
computedRows() { | |||
return this.showUploadComponents | |||
? [ | |||
...this.rows, | |||
[ | |||
{ | |||
assetUpload: true, | |||
key: 'eq-assets', // 用于区分不同的上传组件 | |||
label: '上传资料', | |||
fieldName: 'assets', | |||
subcomponent: AssetsUpload, | |||
}, | |||
], | |||
[ | |||
{ | |||
assetUpload: true, | |||
key: 'eq-pics', // 用于区分不同的上传组件 | |||
label: '上传图片', | |||
fieldName: 'images', | |||
subcomponent: AssetsUpload, | |||
}, | |||
], | |||
] | |||
: this.rows; | |||
}, | |||
}, | |||
methods: { | |||
/** 查询列表 */ | |||
getList() { | |||
@@ -425,6 +493,10 @@ export default { | |||
this.open = false; | |||
this.reset(); | |||
}, | |||
cancelEdit() { | |||
this.showUploadComponents = false; | |||
this.editVisible = false; | |||
}, | |||
/** 表单重置 */ | |||
reset() { | |||
this.form = { | |||
@@ -450,11 +522,13 @@ export default { | |||
handleAdd() { | |||
this.reset(); | |||
this.open = true; | |||
this.showUploadComponents = false; | |||
this.title = '添加设备'; | |||
}, | |||
/** 修改按钮操作 */ | |||
handleUpdate(row) { | |||
this.reset(); | |||
this.showUploadComponents = true; | |||
const id = row.id; | |||
getEquipment(id).then((response) => { | |||
this.form = response.data; | |||
@@ -521,6 +595,7 @@ export default { | |||
viewDetail(id) { | |||
this.reset(); | |||
this.editMode = 'detail'; | |||
this.showUploadComponents = true; | |||
this.form.id = id; | |||
this.editVisible = true; | |||
this.$nextTick(() => { | |||
@@ -533,6 +608,7 @@ export default { | |||
case 'edit': | |||
this.reset(); | |||
this.editMode = 'edit'; | |||
this.showUploadComponents = true; | |||
this.form.id = data.id; | |||
this.editVisible = true; | |||
this.$nextTick(() => { | |||
@@ -43,7 +43,7 @@ export default { | |||
eq.okQuantity, | |||
eq.nokQuantity, | |||
eq.totalQuantity, | |||
eq.passRate.toFixed(4), | |||
eq.passRate?.toFixed(4), | |||
]); | |||
}); | |||
return { | |||