update 附件上传功能

This commit is contained in:
lb 2023-02-17 10:44:29 +08:00
parent beca018db6
commit c2657b190e
12 changed files with 240 additions and 1172 deletions

View File

@ -1,649 +0,0 @@
<template>
<el-dialog
class="super-flexible-dialog"
:title="isDetail ? title.detail : !dataForm.id ? title.add : title.edit"
:visible.sync="visible"
@close="handleClose"
:distory-on-close="true"
:close-on-click-modal="false">
<div style="max-height: 60vh; overflow-y: scroll; overflow-x: hidden">
<el-form ref="dataForm" :model="dataForm" :rules="dataFormRules">
<!-- 如果需要更精细一点的布局可以根据配置项实现地再复杂一点但此处暂时全部采用一行两列布局 -->
<el-row v-for="n in rows" :key="n" :gutter="20">
<el-col v-for="c in COLUMN_PER_ROW" :key="`${n}+'col'+${c}`" :span="getSpan(n, c)">
<!-- <el-col v-for="c in COLUMN_PER_ROW" :key="`${n}+'col'+${c}`" :span="24 / COLUMN_PER_ROW"> -->
<!-- :class="{ 'hidden-input': configs.fields[(n - 1) * COLUMN_PER_ROW + (c - 1)].hidden }" -->
<el-form-item
v-if="configs.fields[(n - 1) * COLUMN_PER_ROW + (c - 1)]"
:prop="configs.fields[(n - 1) * COLUMN_PER_ROW + (c - 1)].name"
:key="`${n}-col-${c}-item`"
:label="getLabel(n, c)">
<!-- 暂时先不实现部分输入方式 -->
<el-input
v-if="getType(n, c) === 'input'"
:placeholder="getPlaceholder(n, c)"
v-model="dataForm[configs.fields[(n - 1) * COLUMN_PER_ROW + (c - 1)].name]"
clearable
:disabled="isDetail" />
<el-radio
v-if="getType(n, c) === 'radio'"
v-model="dataForm[configs.fields[(n - 1) * COLUMN_PER_ROW + (c - 1)].name]"
:disabled="isDetail" />
<el-checkbox
v-if="getType(n, c) === 'check'"
v-model="dataForm[configs.fields[(n - 1) * COLUMN_PER_ROW + (c - 1)].name]"
:disabled="isDetail" />
<el-select
v-if="getType(n, c) === 'select'"
:placeholder="getPlaceholder(n, c)"
v-model="dataForm[configs.fields[(n - 1) * COLUMN_PER_ROW + (c - 1)].name]"
clearable
:disabled="isDetail"
@change="emitSelectChange(configs.fields[(n - 1) * COLUMN_PER_ROW + (c - 1)].name, $event)">
<el-option
v-for="opt in configs.fields[(n - 1) * COLUMN_PER_ROW + (c - 1)].options"
:key="opt.label + Math.random()"
:label="opt.label"
:value="opt.value" />
</el-select>
<el-switch
v-if="getType(n, c) === 'switch'"
v-model="dataForm[configs.fields[(n - 1) * COLUMN_PER_ROW + (c - 1)].name]"
:disabled="isDetail" />
<el-cascader
v-if="getType(n, c) === 'cascader'"
v-model="dataForm[configs.fields[(n - 1) * COLUMN_PER_ROW + (c - 1)].name]"
:options="configs.fields[(n - 1) * COLUMN_PER_ROW + (c - 1)].options"
:props="configs.fields[(n - 1) * COLUMN_PER_ROW + (c - 1)].props"
:disabled="isDetail"
clearable />
<el-time-select
v-if="getType(n, c) === 'time'"
v-model="dataForm[configs.fields[(n - 1) * COLUMN_PER_ROW + (c - 1)].name]"
:disabled="isDetail" />
<el-date-picker
v-if="getType(n, c) === 'date'"
v-bind="configs.fields[(n - 1) * COLUMN_PER_ROW + (c - 1)].props"
:placeholder="getPlaceholder(n, c)"
v-model="dataForm[configs.fields[(n - 1) * COLUMN_PER_ROW + (c - 1)].name]"
:disabled="isDetail" />
</el-form-item>
</el-col>
</el-row>
<!-- extra components , like Markdown or RichEdit -->
<template v-if="configs.extraComponents && configs.extraComponents.length > 0">
<el-form-item
v-for="(ec, index) in configs.extraComponents"
:key="ec.name + index"
:label="ec.label"
class="extra-components">
<component
style="margin-top: 40px"
v-if="ec.hasModel"
:is="ec.component"
v-bind="ec.props"
v-model="dataForm[ec.name]"
@ready="handleEditorReady"
:read-only="isDetail" />
<!-- <component v-if="ec.hasModel" :is="ec.component" v-bind="ec.props" v-model="dataForm[ec.name]" /> -->
<component
v-else
:is="ec.component"
v-bind="ec.props"
@uploader-update-filelist="handleUploadListUpdate($event, ec.props.extraParams.typeCode)"
:uploader-inject-file-list="/*用于设备分流的*/ fileList[ec.props.extraParams.typeCode]"
:read-only="isDetail" />
</el-form-item>
</template>
</el-form>
<!-- <template v-if="dataForm.id && configs.subtable">
<attr-form :related-id="dataForm.id" v-bind="configs.subtable" :is-detail="isDetail" />
</template> -->
</div>
<span slot="footer" class="dialog-footer">
<template v-for="(operate, index) in configs.operations">
<!-- {{ operate.name | btnNameFilter }} -->
<el-button
v-if="
!isDetail &&
(operate.showAlways ||
(((dataForm.id && operate.showOnEdit) || (!dataForm.id && !operate.showOnEdit)) &&
(operate.permission ? $hasPermission(operate.permission) : true)))
"
:key="`operate-${index}`"
:type="btnType[operate.name]"
@click="handleClick(operate)"
>{{ btnName[operate.name] }}</el-button
>
</template>
<el-button v-if="isDetail" @click="handleClick({ name: 'cancel' })">{{ $t('cancel') }}</el-button>
</span>
</el-dialog>
</template>
<script>
// import CKEditor from 'ckeditor4-vue'
// import AttrForm from './AttrForm'
// import { pick } from 'lodash/object'
import { pick as __pick } from '@/utils/filters';
// import i18n from '@/i18n'
import $http from '@/utils/request';
const i18n = {
t: (a) => a,
};
// for i18n
const title = {
// detail: i18n.t('detail'),
// add: i18n.t('add'),
// edit: i18n.t('edit'),
detail: '详情',
add: '添加',
edit: '编辑',
};
//
const btnType = {
save: 'success',
update: 'primary',
reset: 'text',
// cancel: 'text'
// add more...
};
const btnName = {
save: '保存',
update: '更新',
reset: '重置',
cancel: '取消',
// for i18n
// save: i18n.t('save'),
// update: i18n.t('update'),
// reset: i18n.t('reset'),
// cancel: i18n.t('cancel'),
// add more...
};
//
const COLUMN_PER_ROW = 2;
export default {
name: 'AddOrUpdateDialog',
// components: { AttrForm },
props: {
configs: {
type: Object,
default: () => ({}), // 使
},
url: {
type: Object,
default: () => ({}), // 使
},
},
filters: {
nameFilter: function (name) {
if (!name) return null;
// for i18n
const defaultNames = {
name: '名称',
code: '编码',
remark: '备注',
description: '描述',
specifications: '规格',
// name: i18n.t('name'),
// code: i18n.t('code'),
// remark: i18n.t('remark'),
// description: i18n.t('desc'),
// specifications: i18n.t('prod.spec'),
// add more...
};
return defaultNames[name];
},
},
// provide() {
// return {
// _df: this.dataForm
// }
// },
data() {
return {
COLUMN_PER_ROW,
title,
/** 按钮相关属性 */
btnName,
btnType,
defaultNames: {
name: '名称',
code: '编码',
remark: '备注',
description: '描述',
specifications: '规格',
// add more...
// name: i18n.t('name'),
// code: i18n.t('code'),
// remark: i18n.t('remark'),
// description: i18n.t('desc'),
// specifications: i18n.t('prod.spec'),
// add more...
},
defaultPlaceholders: {}, // defaultNames
/** 表单相关属性 */
visible: false,
isEdit: false,
isDetail: false,
dataForm: {},
dataFormRules: {},
tempForm: [], // code
shouldWait: null,
fileForm: {}, // typeCode
fileList: {}, // typeCode
};
},
computed: {
rows() {
// ''
return Math.ceil(this.configs.fields.length / COLUMN_PER_ROW);
},
},
created() {
/** load lang */
// CKEditor.load()
// console.log('lang', CKEditor.component.props.config.defaultLanguage = 'en' )
},
mounted() {
/** 计算 defaultPlaceholders */
// const prefix = i18n.t('hints.input');
const prefix = '请输入';
Object.entries(this.defaultNames).map(([key, value]) => {
this.defaultPlaceholders[key] = prefix + value;
});
/** 转换 configs.fields 的结构,把纯字符串转为对象 */
this.$nextTick(() => {
this.configs.fields = this.configs.fields.map((item) => {
if (typeof item === 'string') {
return { name: item };
}
return item;
});
/** 动态设置dataForm字段 */
this.configs.fields.forEach((item) => {
this.$set(this.dataForm, [item.name], '');
/** select 的默认值设置 */
if (item.type === 'select') {
const opts = item.options || [];
const dft = opts.find((item) => item.default || false);
if (dft) {
this.$set(this.dataForm, [item.name], dft.value);
}
}
if (item.api) {
/** 自动请求并填充 */
// or this.shouldWaitPool = []
this.shouldWait =
// this.$http({
// url: this.$http.adornUrl(item.api),
// method: 'POST', //
// })
$http
.get(item.api)
// .then(({ data: res }) => {
.then((res) => {
if (res && res.code === 0) {
// this.dataForm[item.name] = res.data // <===
this.tempForm.push({ name: item.name, data: res.data });
}
});
} // end if (item.api)
// relatedFielditem relatedField
if (item.relatedField) {
this.$watch(
function () {
return this.dataForm[item.name];
},
function (val, old) {
if (val && val !== old) {
this.$emit('select-change', { name: item.name, id: val });
}
},
{ deep: true, immediate: true }
);
}
if (item.required) {
const requiredRule = {
required: true,
message: '必填项',
// message: i18n.t('validate.required'),
// trigger: 'change'
trigger: 'blur',
};
/** 检查是否已经存在该字段的规则 */
const exists = this.dataFormRules[item.name] || null;
/** 设置验证规则 */
if (exists) {
const unset = true;
for (const rule of exists) {
if (rule.required) unset = false;
}
if (unset) {
exists.push(requiredRule);
}
} else {
/** 不存在已有规则 */
this.$set(this.dataFormRules, [item.name], [requiredRule]);
}
} // end if (item.required)
if (item.rules) {
const exists = this.dataFormRules[item.name] || null;
if (exists) {
//
exists.push(...item.rules);
} else {
this.$set(this.dataFormRules, [item.name], [...item.rules]);
}
} // end if (item.rules)
});
/** 计算默认值 */
function calDefault(type) {
switch (type) {
case 'array':
return [];
// more case...
default:
return '';
}
}
/** 检查是否需要额外的组件 */
this.configs.extraComponents &&
this.configs.extraComponents.forEach((item) => {
// if (Object.hasOwn(this.dataForm, [item.name])) {
if (this.dataForm.hasOwnProperty(item.name)) {
return;
} else {
this.$set(this.dataForm, [item.name], calDefault(item.fieldType));
}
});
/** 单独设置 id */
this.$set(this.dataForm, 'id', null);
});
},
methods: {
getSpan(n, c) {
const opt = this.configs.fields[(n - 1) * COLUMN_PER_ROW + (c - 1)];
return opt && opt.span ? opt.span : 24 / COLUMN_PER_ROW;
},
getLabel(n, c) {
const opt = this.configs.fields[(n - 1) * COLUMN_PER_ROW + (c - 1)];
if (opt) {
// if opt is valid
return opt.label ? opt.label : this.defaultNames[opt.name];
}
},
getPlaceholder(n, c) {
if (this.isDetail) {
/** 如果是详情,就不展示 提示文本 */
return '';
}
const opt = this.configs.fields[(n - 1) * COLUMN_PER_ROW + (c - 1)];
if (opt) {
// if opt is valid
return opt.placeholder
? opt.placeholder
: this.defaultPlaceholders[opt.name]
? this.defaultPlaceholders[opt.name]
: opt.label
? (opt.type === 'select' ? '请选择' : '请输入') + opt.label
: // ? (opt.type === 'select' ? i18n.t('choose') : i18n.t('hints.input')) + opt.label
null;
// : opt.type === 'select'
// ? i18n.t('choose')
// : ''
}
},
getType(n, c) {
const opt = this.configs.fields[(n - 1) * COLUMN_PER_ROW + (c - 1)];
if (opt) {
if (!opt.type || ['input', 'number' /** add more.. */].includes(opt.type)) {
return 'input';
} else if (['select' /** add more.. */].includes(opt.type)) {
return 'select';
} else if (['cascader'].includes(opt.type)) {
return 'cascader';
} else if (['date'].includes(opt.type)) {
return 'date';
}
// add more...
} else {
return 'input';
}
},
init(id, isdetail = false) {
this.isDetail = isdetail;
this.visible = true;
this.$nextTick(() => {
this.$refs['dataForm'].resetFields();
this.dataForm.id = id || null;
if (this.dataForm.id) {
// this.$http({
// url: this.$http.adornUrl(`${this.configs.infoUrl}/${this.dataForm.id}`),
// method: 'get'
// })
$http.get(this.url.base + `/${this.dataForm.id}`).then((res) => {
console.log('[base dialog init] ', res);
if (res && res.code === 0) {
const dataFormKeys = Object.keys(this.dataForm);
console.log('keys ===> ', dataFormKeys);
// console.log('data form keys: ', dataFormKeys, pick(res.data, dataFormKeys))
this.dataForm = __pick(res.data, dataFormKeys);
console.log('pick(res.data, dataFormKeys) ===> ', __pick(res.data, dataFormKeys));
// LABEL: FILE_RELATED
/** 对文件下载进行分流 */
this.fileList = {};
if (this.dataForm.files) {
// console.log('files: ', this.dataForm.files)
this.dataForm.files.forEach((file) => {
// const fileName = file.fileUrl.split('/').pop()
/** [1] 处理 fileList */
// if (Object.hasOwn(this.fileList, file.typeCode)) {
if (this.fileList.hasOwnProperty(file.typeCode)) {
/** 已存在 */
// this.fileList[file.typeCode].push({ id: file.id, name: fileName, typeCode: file.typeCode })
this.fileList[file.typeCode].push(file);
} else {
// this.fileList[file.typeCode] = [{ id: file.id, name: fileName, typeCode: file.typeCode }]
this.fileList[file.typeCode] = [file];
}
/** [2] 处理 fileForm */
// if (Object.hasOwn(this.fileForm, file.typeCode)) {
if (this.fileForm.hasOwnProperty(file.typeCode)) {
this.fileForm[file.typeCode].push(file.id);
} else {
this.fileForm[file.typeCode] = [file.id];
}
});
}
}
});
} else {
/** 如果不是编辑,就填充自动生成的数据 */
if (this.shouldWait)
this.shouldWait.then(() => {
if (this.tempForm.length) {
// console.log('create new, tempform', JSON.stringify(this.tempForm.length))
this.tempForm.forEach((item) => {
// console.log('item data', item.data)
this.dataForm[item.name] = item.data;
});
// console.log('create new, dataform', JSON.stringify(this.dataForm))
}
this.shouldWait = null;
});
}
});
},
emitSelectChange(name, id) {
const currentField = this.configs.fields.find((item) => item.name === name);
if (currentField.relatedField) {
this.dataForm[currentField.relatedField] = null;
}
this.$emit('select-change', { name, id });
},
handleEditorReady(val) {},
handleClick(btn) {
/** 提取url */
// const urls = {};
// this.configs.operations.map((item) => {
// urls[item.name] = {};
// urls[item.name].url = item.url;
// urls[item.name].extraFields = item.extraFields || {};
// });
/** 操作 */
switch (btn.name) {
case 'save':
case 'update':
/** 需要验证表单的操作 */
this.$refs['dataForm'].validate((valid) => {
if (valid) {
/** 对于文件上传的单独处理(合并处理) */
if (Object.keys(this.fileForm).length) {
// LABEL: FILE_RELATED
let fileIds = [];
for (const [key, item] of Object.entries(this.fileForm)) {
if (Array.isArray(item)) {
fileIds = fileIds.concat(item);
} else {
console.error('handleClick(): 上传文件数组类型不正确');
}
}
this.$set(this.dataForm, 'fileIds', fileIds);
}
// console.log('before send: ', this.dataForm)
// this.$http({
// url: this.$http.adornUrl(urls[btn.name].url),
// method: btn.name === 'save' ? 'POST' : 'PUT',
// data: { ...this.dataForm, ...urls[btn.name].extraFields },
// })
$http[btn.name === 'save' ? 'post' : 'put'](btn.url, { ...this.dataForm, ...btn.extraFields })
.then((res) => {
// .then(({ data: res }) => {
console.log('save res: ', res, btn.name, this.dataForm);
if (res && res.code === 0) {
this.$message({
message: '操作成功!',
// message: i18n.t('prompt.success'),
// message: btn.name === 'save' ? i18n.t('prompt.success') : '!',
type: 'success',
duration: 1500,
onClose: () => {
this.$emit('refreshDataList');
this.visible = false;
},
});
} else {
this.$message.error(res.msg);
}
})
.catch((err) => {
this.$message({
message: err,
type: 'error',
duration: 2000,
});
});
}
});
return;
case 'reset':
for (const key of Object.keys(this.dataForm)) {
if (typeof this.dataForm[key] === 'string') {
this.dataForm[key] = '';
} else if (this.dataForm[key] instanceof Array) {
this.dataForm[key].splice(0);
} else {
this.dataForm[key] = null;
}
}
break;
case 'cancel':
this.handleClose();
// add more..
}
},
// LABEL: FILE_RELATED
handleUploadListUpdate(filelist, typeCode = 'DefaultTypeCode') {
// console.log('before handleUploadListUpdate(): ', JSON.parse(JSON.stringify(this.fileForm)))
// typeCode: EquipmentTypeFile
// typeCode: EquipmentInfoFile | EquipmentInfoImage
// dataForm
// this.$set(
// this.dataForm,
// 'fileIds',
// filelist.map(item => item.id)
// )
// console.log('handleUploadListUpdate(): ', this.dataForm)
//
this.$set(
this.fileForm,
typeCode,
filelist.map((item) => item.id)
);
// console.log('after handleUploadListUpdate(): ', this.fileForm)
},
handleClose() {
this.$emit('destory-dialog');
this.visible = false;
},
},
};
</script>
<style scoped>
.super-flexible-dialog >>> .el-select,
.super-flexible-dialog >>> .el-cascader {
width: 100%;
}
.super-flexible-dialog >>> ::-webkit-scrollbar {
width: 4px;
border-radius: 4px;
background: #fff;
}
.super-flexible-dialog >>> ::-webkit-scrollbar-thumb {
width: 4px;
border-radius: 4px;
background: #ccc;
}
.super-flexible-dialog >>> .hidden-input {
display: none;
}
</style>

View File

@ -1,181 +0,0 @@
<template>
<el-row class="base-search-form">
<div class="brand-color-line"></div>
<el-form :inline="true" :model="searchForm" :rules="headConfig.rules">
<!-- <el-col :span="opt.span ? +opt.span : 4" v-for="opt in options" :key="opt.id"> -->
<el-form-item
v-for="(opt, index) in headConfig.fields"
:key="opt.prop"
:label="opt.label ? opt.label : null"
:prop="'' + index"
:rules="opt.bind?.rules ? opt.bind.rules : undefined"
>
<el-input
v-if="opt.input"
v-model="searchForm[index]"
v-bind="opt.bind"
/>
<el-select
v-if="opt.select"
v-model="searchForm[index]"
v-bind="opt.bind"
>
<el-option
v-for="item in opt.select"
:key="item.value"
:label="item.label"
:value="item.value"
/>
</el-select>
<el-date-picker
v-if="opt.timerange"
v-model="searchForm[index]"
v-bind="opt.bind"
/>
<el-upload
v-if="opt.upload"
:key="'upload_' + Math.random().toString()"
class="inline-block pl-3"
action="https://jsonplaceholder.typicode.com/posts/"
>
<el-button type="primary">上传文件</el-button>
</el-upload>
<el-button
v-if="
opt.button &&
(!opt.button.permission || $hasPermission(opt.button.permission))
"
:key="'button' + Math.random().toString()"
:type="opt.button.type"
@click="handleBtnClick(opt.button.name)"
>{{ opt.button.name }}</el-button
>
</el-form-item>
</el-form>
</el-row>
</template>
<script>
export default {
name: "",
props: {
headConfig: {
type: Object,
default: () => ({}),
},
},
data() {
return {
searchForm: {
// 10
0: null, //
1: null,
2: null,
3: null,
4: null,
5: null,
6: null,
7: null,
8: null,
9: null,
},
};
},
watch: {
searchForm: {
handler: (val) => {
console.log("new val", val);
},
deep: true,
},
},
created() {},
mounted() {
console.log(
"head form config",
JSON.parse(JSON.stringify(this.headConfig))
);
this.headConfig.fields.forEach((field, index) => {
if (field.default) {
// default value input
this.searchForm[index] = field.default.value;
}
//
if (!field.watch && field.fn && typeof field.fn === "function") {
//
field.fn().then((res) => {
field.select = res.map((_) => {
//
if (_.default) {
this.searchForm[index] = _.value;
}
return _;
});
console.log("[update] 更新选项列表", res, field.select);
});
}
//
if (field.watch) {
const { index: innerIdx, condition } = field.watch;
console.log(
"=====field.watch=====",
innerIdx,
this.searchForm[innerIdx],
this.headConfig.fields[innerIdx].default
);
//
this.$watch(
() => this.searchForm[innerIdx],
(val) => {
const queryParams = { [condition]: val };
// field.watch.condition.forEach(c => {
// queryParams
// })
this.$http(field.url, queryParams).then((res) => {
console.log("[==>] 更新有前置条件的字段!!!", queryParams, res);
// index
this.searchForm[index] = Math.floor(Math.random() * 10);
});
}
);
console.log("[BaseSearchForm] mounted(): ", this.searchForm);
//
if (this.searchForm[innerIdx]) {
// TODO: ...
console.log("TODO: 这个判断好像不太需要...");
} else {
console.log("TODO: 监听的字段还没来得及设置值呢...");
}
}
});
},
methods: {
handleBtnClick(name) {
this.$emit("btn-click", { btnName: name, payload: this.searchForm });
},
},
};
</script>
<style scoped>
.base-search-form {
display: flex;
/* align-items: center; */
/* position: relative; */
}
.brand-color-line {
display: inline-block;
height: 20px;
width: 6px;
margin-right: 8px;
margin-top: 10px;
border-radius: 2px;
background: #0b58ff;
/* position: absolute; */
}
</style>

View File

@ -1,206 +0,0 @@
<!--
* @Date: 2020-12-14 09:07:03
* @LastEditors: gtz
* @LastEditTime: 2022-06-13 08:59:21
* @FilePath: \mt-bus-fe\src\components\BaseTable\index.vue
* @Description:
-->
<template>
<div class="">
<el-table
:header-cell-style="{
background: '#FAFAFA',
color: '#606266',
height: '40px',
}"
:data="renderData"
:show-header="showHeader"
:border="border"
fit
highlight-current-rows
style="width: 100%"
@row-click="handleRowClick"
@selection-change="handleSelectionChange"
>
<!-- :max-height="height ? height : tableHeight(325)" -->
<el-table-column v-if="sbox" type="selection" width="55" fixed />
<el-table-column
v-if="page && limit && !toggleCustomIndex"
prop="_pageIndex"
:label="'tableHeader.index' | i18nFilter"
width="70"
align="center"
fixed
/>
<el-table-column
v-for="item in renderTableHeadList"
:key="item.prop"
v-bind="item"
:align="item.align ? item.align : 'left'"
:min-width="item.minWidth ? item.minWidth : 150"
:fixed="item.isFixed ? true : false"
:show-overflow-tooltip="true"
>
<template slot-scope="scope">
<component
:is="item.subcomponent"
v-if="item.subcomponent"
:key="scope.row.id"
:inject-data="{ ...scope.row, ...item }"
@emitData="emitData"
/>
<span v-else>{{
scope.row[item.prop] | commonFilter(item.filter)
}}</span>
</template>
</el-table-column>
<slot name="content" />
<slot name="handleBtn" />
</el-table>
</div>
</template>
<script>
export default {
name: "BaseTable",
filters: {
commonFilter: (source, filterType = (a) => a) => {
return filterType(source);
},
},
props: {
toggleCustomIndex: {
type: Boolean,
default: false,
},
topBtnConfig: {
type: Array,
default: () => {
return [];
},
},
showHeader: {
type: Boolean,
default: true,
},
border: {
type: Boolean,
default: false,
},
height: {
type: Number,
required: false,
default: 0,
},
tableData: {
type: Array,
required: true,
// validator: (val) => val.filter((item) => !isObject(item)).length === 0,
},
tableConfig: {
type: Array,
required: true,
// validator: (val) =>
// val.filter((item) => !isString(item.prop) || !isString(item.label))
// .length === 0,
},
isLoading: {
type: Boolean,
required: false,
},
page: {
type: Number,
required: false,
default: 0,
},
limit: {
type: Number,
required: false,
default: 0,
},
sbox: {
type: Boolean,
required: false,
},
highIndex: {
//
type: Boolean,
required: false,
},
},
data() {
return {
tableConfigBak: [],
selectedBox: new Array(100).fill(true),
// tableHeight,
tableRowIndex: null,
};
},
computed: {
renderData() {
return this.tableData.map((item, index) => {
return {
...item,
_pageIndex: (this.page - 1) * this.limit + index + 1,
};
});
},
renderTableHeadList() {
return this.tableConfig.filter((item, index) => {
return this.selectedBox[index];
});
},
},
watch: {
tableData: function (val) {
if (this.highIndex) {
//
this.tableRowIndex = 0;
}
},
},
beforeMount() {
this.selectedBox = new Array(100).fill(true);
if (this.highIndex) {
this.tableRowIndex = 0;
}
},
// mounted() {
// this.tableConfigBak = cloneDeep(this.tableConfig).map(item => {
// return {
// ...item,
// selected: true
// }
// })
// },
methods: {
emitData(val) {
this.$emit("emitFun", val);
},
clickTopButton(val) {
this.$emit("clickTopBtn", val);
},
handleSelectionChange(val) {
this.$emit("selectChangeFun", val);
},
handleRowClick(row) {
this.tableRowIndex = this.getArrayIndex(this.tableData, row); //
this.$emit("selectRow", row);
},
tableRowClassName({ row, rowIndex }) {
if (rowIndex === this.tableRowIndex) {
return "success-row";
}
return "";
},
getArrayIndex(arr, obj) {
var i = arr.length;
while (i--) {
if (arr[i].id === obj.id) {
return i;
}
}
return -1;
},
},
};
</script>

View File

@ -1,19 +0,0 @@
<!-- 基本上传 -->
<template>
<div></div>
</template>
<script>
export default {
name: '',
props: {},
data() {
return {};
},
created() {},
mounted() {},
methods: {},
};
</script>
<style scoped></style>

View File

@ -210,6 +210,8 @@ export default {
url: file.url,
typeCode: file.typeCode,
}));
//
this.addOrUpdate("PUT");
},
/** utitilities */
@ -265,7 +267,7 @@ export default {
url: file.fileUrl,
}));
}
console.log("[DialogJustForm] init():", __pick(res.data, Object.keys(this.dataForm)));
console.log("[DialogJustForm] init():", this.dataForm);
}
this.loadingStatus = false;
});
@ -290,6 +292,53 @@ export default {
console.log("[DialogJustForm] handleComponentModelUpdate", this.dataForm[propName]);
},
addOrUpdate(method = "POST") {
if ("parentId" in this.dataForm) {
console.log("[DialogJustForm parentId]", this.dataForm.parentId);
// parentId cascader ["xxx"]xxx
const lastItem = this.dataForm.parentId.length - 1;
this.dataForm.parentId = this.dataForm.parentId[lastItem];
}
this.$refs.dataForm.validate((passed, result) => {
if (passed) {
this.loadingStatus = true;
let httpPayload = null;
/** 针对有文件上传选项的弹窗提供特殊的 payload */
if (this.dataForm.files) {
httpPayload = {
...this.dataForm,
fileIds: this.dataForm.files.map((file) => file.id),
};
} else {
httpPayload = this.dataForm;
}
/** 发送 */
return this.$http({
url: this.urls.base,
method,
data: httpPayload,
})
.then(({ data: res }) => {
console.log("[add&update] res is: ", res);
if (res.code === 0) {
this.$message.success(method === "POST" ? "添加成功" : "更新成功");
this.$emit("refreshDataList");
this.loadingStatus = false;
if (method === "POST") this.handleClose();
}
})
.catch((errMsg) => {
this.$message.error("参数错误:" + errMsg);
if (this.loadingStatus) this.loadingStatus = false;
});
} else {
this.$message.error("请核查字段信息");
}
});
},
handleBtnClick(payload) {
console.log("btn click payload: ", payload);
@ -302,52 +351,9 @@ export default {
this.resetForm(true, true); // true means exclude id, immediate execution
break;
case "add":
case "update": {
if ("parentId" in this.dataForm) {
console.log("[DialogJustForm parentId]", this.dataForm.parentId);
// parentId cascader ["xxx"]xxx
const lastItem = this.dataForm.parentId.length - 1;
this.dataForm.parentId = this.dataForm.parentId[lastItem];
}
this.$refs.dataForm.validate((passed, result) => {
if (passed) {
this.loadingStatus = true;
const method = payload.name === "add" ? "POST" : "PUT";
let httpPayload = null;
/** 针对有文件上传选项的弹窗提供特殊的 payload */
if (this.dataForm.files) {
httpPayload = {
...this.dataForm,
fileIds: this.dataForm.files.map((file) => file.id),
};
} else {
httpPayload = this.dataForm;
}
/** 发送 */
this.$http({
url: this.urls.base,
method,
data: httpPayload,
})
.then(({ data: res }) => {
console.log("[add&update] res is: ", res);
if (res.code === 0) {
this.$message.success(payload.name === "add" ? "添加成功" : "更新成功");
this.$emit("refreshDataList");
this.loadingStatus = false;
this.handleClose();
}
})
.catch((errMsg) => {
this.$message.error("参数错误:" + errMsg);
if (this.loadingStatus) this.loadingStatus = false;
});
} else {
this.$message.error("请核查字段信息");
}
});
}
case "update":
this.addOrUpdate((payload.name === "add" ? "POST" : "PUT"));
break;
}
} else {
console.log("[x] 不是这么用的! 缺少name属性");

View File

@ -32,6 +32,7 @@
:show-file-list="false"
:headers="uploadHeaders"
:on-success="handleUploadSuccess"
:before-upload="handleUploadCheck"
>
<el-button plain type="primary" size="small" class="at-right-top" style=""> <i class="el-icon-upload"></i> 上传 </el-button>
</el-upload>
@ -128,6 +129,7 @@
:current-page="attrPage"
:current-size="attrSize"
:refresh-layout-key="Math.random()"
v-loading="loadingStatus"
/>
<!-- paginator -->
<el-pagination
@ -147,8 +149,9 @@
<!-- 附件标签页 -->
<div v-if="dataForm.id && tab.key === 'attachment'" key="attachment">
<div class="upload-tips" style="font-size: 0.8em; margin-bottom: 12px">文件大小不要超过 2MB</div>
<!-- 附件列表 -->
<div class="">
<div class="" v-loading="loadingStatus">
<ul class="file-list">
<li v-for="(file, index) in fileList" :key="index">
<span class="file-name">{{ file.name }}</span>
@ -166,11 +169,17 @@
</li>
</ul>
</div>
<!-- 提示信息 -->
<!-- img preview dialog -->
<el-dialog key="image-preview-dialog" class="image-preview-dialog" :visible.sync="imgPreviewDialogVisible" :append-to-body="true">
<div class="img-container">
<img width="100%" :src="currentImgUrl" alt="" />
</div>
</el-dialog>
</div>
</el-tab-pane>
</el-tabs>
</div>
<!-- sub dialog -->
<small-dialog
:append-to-body="true"
@ -341,7 +350,9 @@ export default {
attrPage: 1,
attrSize: 5,
attrTotal: 0,
fileList: [{ name: "1.png" }, { name: "2.png" }],
fileList: [],
imgPreviewDialogVisible: false,
currentImgUrl: "",
};
},
computed: {
@ -377,8 +388,10 @@ export default {
const editMode = operate.showOnEdit && this.dataForm.id;
const addMode = !operate.showOnEdit && !this.dataForm.id;
const permission = operate.permission ? this.$hasPermission(operate.permission) : true;
return notDetailMode && (showAlways || ((editMode || addMode) && permission));
const currentMenuKey = this.configs.menu.find((item) => item.name === this.activeMenu)?.key;
return notDetailMode && (showAlways || ((editMode || addMode) && permission)) && currentMenuKey === "info";
},
resetForm(excludeId = false, immediate = false) {
setTimeout(
() => {
@ -399,7 +412,7 @@ export default {
},
/** init **/
init(id, detailMode) {
init(id, detailMode, menu) {
// this.dialogVisible = true;
if (this.$refs.dataForm && this.$refs.dataForm.length) {
// dialog dataForm [0]
@ -434,6 +447,10 @@ export default {
}
}
this.loadingStatus = false;
//
if (menu && menu.key === "attachment") {
this.activeMenu = this.configs.menu.find((item) => item.key === menu.key)?.name;
}
});
} else {
//
@ -445,31 +462,97 @@ export default {
/** handlers */
handleFileClick(type, file) {
switch (type) {
case "view":
break;
case "download": {
/** 通知 */
this.$notify({
title: "成功",
message: "开始下载",
type: "success",
});
case "view": {
//
this.$http
.get("/pms/attachment/downloadFile", {
params: {
attachmentId: file.id,
type: 0, // 0 1
},
responseType: "blob",
})
.then(({ data: res }) => {
console.log("preivew", res);
if (/image/i.test(res.type)) {
//
this.currentImgUrl = URL.createObjectURL(res);
this.imgPreviewDialogVisible = true;
} else {
this.$message({
message: "非图片文件请下载后预览",
type: "error",
duration: 1500,
});
}
});
break;
}
case "delete": {
console.log("deleting", file);
const { id } = file;
this.fileList = this.fileList.filter((f) => f.id !== id);
this.updateRemoteFiles().then((res) => {
/** 通知 */
this.$notify({
title: "成功",
message: "已删除",
type: "success",
case "download": {
//
this.$http
.get("/pms/attachment/downloadFile", {
params: {
attachmentId: file.id,
type: 1, // 0 1
},
responseType: "blob",
})
.then(({ data: res }) => {
const blob = new Blob([res]);
/** 通知 */
this.$notify({
title: "成功",
message: "开始下载",
type: "success",
duration: 1200,
});
if ("download" in document.createElement("a")) {
const alink = document.createElement("a");
alink.download = file.name;
alink.style.display = "none";
alink.target = "_blank";
alink.href = URL.createObjectURL(blob);
document.body.appendChild(alink);
alink.click();
URL.revokeObjectURL(alink.href);
document.body.removeChild(alink);
} else {
navigator.msSaveBlob(blob, fileName);
}
});
});
break;
}
case "delete": {
return this.$confirm(`确定删除图片: ${file.name}`, "提示", {
confirmButtonText: "确认",
cancelButtonText: "我再想想",
type: "warning",
})
.then(() => {
this.loadingStatus = true;
const newFilelist = this.fileList.filter((f) => f.id !== file.id);
this.updateRemoteFiles(newFilelist).then((msg) => {
if (msg && msg === "success") {
this.fileList = newFilelist;
this.loadingStatus = false;
/** 通知 */
this.$notify({
title: "成功",
message: "已删除",
type: "success",
duration: 1200,
});
}
});
})
.catch((err) => {});
}
}
},
@ -485,31 +568,47 @@ export default {
typeCode: file.typeCode,
};
this.fileList.push(fileItem);
/** 通知 */
this.$notify({
title: "成功",
message: "上传成功",
type: "success",
this.loadingStatus = true;
this.updateRemoteFiles([...this.fileList, fileItem]).then((msg) => {
if (msg && msg === "success") {
this.fileList.push(fileItem);
this.loadingStatus = false;
/** 通知 */
this.$notify({
title: "成功",
message: "上传成功",
type: "success",
duration: 1200,
});
}
});
this.updateRemoteFiles();
}
},
updateRemoteFiles() {
updateRemoteFiles(filelist) {
return this.$http
.put("/pms/product", {
id: "id" in this.dataForm ? this.dataForm.id : "DEFAULT_ID",
// code: "code" in this.dataForm ? this.dataForm.code : "DEFAULT_CODE",
// ...this.dataForm,
fileIds: this.fileList.map((f) => f.id),
fileIds: filelist.map((f) => f.id),
})
.then(({ data: res }) => {
console.log("updateFileList", this.fileList, res);
if (res.code === 0) return "success";
});
},
handleUploadCheck(file) {
console.log("[before upload]", file);
const LIMIT = 2 * 1024 * 1024; // bytes
if (file.size > LIMIT) {
this.$message({
message: "文件大小不能超过 2MB",
type: "error",
duration: 1500,
});
return false;
} else return true;
},
handleComponentModelUpdate(propName, { subject, payload: { data } }) {
this.dataForm[propName] = JSON.stringify(data);
console.log("[DialogJustForm] handleComponentModelUpdate", this.dataForm[propName]);
@ -538,6 +637,15 @@ export default {
//
this.loadingStatus = true;
const method = payload.name === "add" ? "POST" : "PUT";
//
const hasAttachment = !!this.configs.menu.find((item) => item.key === "attachment");
if (hasAttachment) {
const fileIds = this.fileList.map((item) => item.id);
this.$set(this.dataForm, "fileIds", fileIds);
}
//
this.$http({
url: this.urls.base,
method,
@ -555,15 +663,11 @@ export default {
if (this.loadingStatus) this.loadingStatus = false;
});
} else {
//
// this.$message.error(JSON.stringify(result));
this.$message.error("请核查字段信息");
}
});
}
}
} else {
console.log("[x] 不是这么用的! 缺少name属性");
}
},
handleTabClick(payload) {
@ -764,4 +868,7 @@ ul.file-list > li:hover {
width: 16px;
height: 16px;
}
/* .image-preview-dialog {
} */
</style>

View File

@ -1,2 +0,0 @@
配置文件选项总结

View File

@ -1,2 +0,0 @@
// 表格中的可点击文本
export default {}

View File

@ -53,8 +53,8 @@ export default {
},
detailMode: {
type: Boolean,
default: false
}
default: false,
},
},
data() {
return {
@ -83,9 +83,19 @@ export default {
attachmentId: file.id,
type: 1,
},
responseType: "blob",
})
.then(({ data: res }) => {
const blob = new Blob([res]);
/** 通知 */
this.$notify({
title: "成功",
message: "开始下载",
type: "success",
duration: 1200,
});
if ("download" in document.createElement("a")) {
const alink = document.createElement("a");
alink.download = file.name;

View File

@ -8,6 +8,7 @@
:show-file-list="false"
:headers="uploadHeaders"
:on-success="handleUploadSuccess"
:before-upload="handleUploadCheck"
>
<el-button :disabled="disabled" size="small" type="primary">{{ buttonText }}</el-button>
<div slot="tip" class="el-upload__tip">
@ -42,7 +43,7 @@ export default {
tips: {
type: Object,
default: () => ({
hint: "只能上传jpg/png文件, 且不超过500kb",
hint: "文件大小不超过 2MB",
success: "上传成功!",
}),
},
@ -64,14 +65,9 @@ export default {
return { showMsg: false, uploadedFileList: [] };
},
watch: {
// fileList: {
// handler: (arr) => {
// if (arr && arr.length > 0) {
// this.uploadedFileList = arr;
// }
// },
// immediate: true,
// },
fileList(val) {
this.uploadedFileList = val ?? [];
}
},
computed: {
uploadHeaders() {
@ -103,6 +99,18 @@ export default {
.catch(() => {});
},
handleUploadCheck(file) {
const LIMIT = 2 * 1024 * 1024; // bytes
if (file.size > LIMIT) {
this.$message({
message: "文件大小不能超过 2MB",
type: "error",
duration: 1500,
});
return false;
} else return true;
},
handleUploadSuccess(response, file, fileList) {
console.log("[UploadBtn] uploadedFileList", response, file, fileList, this.uploadedFileList);
@ -115,13 +123,6 @@ export default {
typeCode: file.typeCode,
};
/** 通知 */
this.$notify({
title: "成功",
message: "上传成功",
type: "success",
});
this.uploadedFileList.push(fileItem);
this.$emit("update-file-list", this.uploadedFileList);
// this.showMsg = true;

View File

@ -224,12 +224,12 @@ export default {
break;
}
case "status": {
console.log('status', data)
console.log("status", data);
// TODO:
const { id, code } = data;
const queryCondition = { id, code };
if ("enabled" in data) queryCondition.enabled = data['enabled'];
if ("status" in data) queryCondition.status = data['status'];
if ("enabled" in data) queryCondition.enabled = data["enabled"];
if ("status" in data) queryCondition.status = data["status"];
// id code enabled
this.$http.put(this.urls.base, queryCondition).then(({ data: res }) => {
if (res.code === 0) {
@ -238,6 +238,9 @@ export default {
});
break;
}
case "view-attachment": {
this.openDialog(data, false, { key: "attachment" });
}
}
},
@ -268,11 +271,11 @@ export default {
},
/** 打开对话框 */
openDialog(row_id, detail_mode) {
openDialog(row_id, detail_mode, tag_info) {
this.dialogVisible = true;
this.$nextTick(() => {
this.$refs["edit-dialog"].init(/** some args... */ row_id, detail_mode);
this.$refs["edit-dialog"].init(/** some args... */ row_id, detail_mode, tag_info);
});
},
},

View File

@ -15,7 +15,7 @@ export default function () {
{ prop: "weight", label: "重量", filter: (val) => (val ? val + " kg" : "-") },
{ prop: "processTime", label: "产线完成单位产品用时", width: 200, filter: (val) => val + " s" },
{ prop: "remark", label: "备注" },
{ prop: "description", label: "附件信息", subcomponent: TableTextComponent, buttonContent: "查看附件" },
{ prop: "description", label: "附件信息", subcomponent: TableTextComponent, buttonContent: "查看附件", actionName: 'view-attachment' },
{
prop: "operations",
name: "操作",