pms-aomei/src/views/atomViews/ListViewWithHead.vue
2023-08-25 15:21:27 +08:00

878 lines
27 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<!-- 表格页加上搜索条件 -->
<template>
<div class="list-view-with-head" ref="pointer-loading-ref">
<!-- <head-form :form-config="headFormConfig" @headBtnClick="btnClick" /> -->
<BaseSearchForm :head-config="headConfig" @btn-click="handleBtnClick" />
<BaseListTable
v-loading="tableLoading"
:table-config="tableConfig.table"
:column-config="tableConfig.column"
:table-data="dataList"
@operate-event="handleOperate"
:current-page="page"
:current-size="size"
@select="handleTableSelect"
:select-props="tableConfig.selectProps ?? []"
:refresh-layout-key="refreshLayoutKey" />
<el-pagination
v-if="navigator"
class="mt-5 flex justify-end"
@size-change="handleSizeChange"
@current-change="handlePageChange"
:current-page.sync="page"
:page-size.sync="size"
:page-sizes="[10, 20, 50, 100]"
:total="totalPage"
layout="total, sizes, prev, pager, next, jumper"></el-pagination>
<DialogWithMenu
ref="edit-dialog"
v-if="!!dialogConfigs && dialogType === DIALOG_WITH_MENU"
:dialog-visible.sync="dialogVisible"
:configs="dialogConfigs"
@refreshDataList="getList" />
<DialogJustForm
ref="edit-dialog"
v-if="!!dialogConfigs && dialogType === DIALOG_JUST_FORM"
:dialog-visible.sync="dialogVisible"
:configs="dialogConfigs"
@refreshDataList="getList"
@emit-data="handleOperate" />
<DialogCarPayload
ref="car-payload-dialog"
v-if="!!carPayloadDialogConfigs"
:dialog-visible.sync="carPayloadDialogVisible"
:configs="carPayloadDialogConfigs"
@refreshDataList="getList" />
<AttachmentDialog ref="attachmentDialog" v-if="needAttachmentDialog" />
<DialogUpload
ref="upload-dialog"
v-if="uploadDialogVisible"
title="导入配方"
filename="bomTemplate.xlsx"
@refresh-list="getList"
@uploadSuccess="getList"
@destroy-dialog="
() => {
uploadDialogVisible = false;
}
" />
<Overlay v-if="overlayVisible" />
<PrintDom ref="print" v-if="printDOMmount" @destroy="printDOMmount = false" @refresh-list="getList" />
<ReportDialog
ref="car-report-dialog"
v-if="carReportDialogVisible"
@destroy="carReportDialogVisible = false"
@refresh-list="getList"
:ids="tableSelectedIds" />
<PalletDialog
ref="pallet-dialog"
v-if="palletDialogVisible"
@destroy="palletDialogVisible = false"
@refresh-list="getList"
:ids="tableSelectedIds" />
</div>
</template>
<script>
import BaseListTable from "@/components/BaseListTable.vue";
import BaseSearchForm from "@/components/BaseSearchForm.vue";
import DialogWithMenu from "@/components/DialogWithMenu.vue";
import DialogJustForm from "@/components/DialogJustForm.vue";
import DialogCarPayload from "@/components/DialogCarPayload.vue";
import DialogUpload from "@/components/DialogUpload.vue";
import Overlay from "@/components/Overlay.vue";
import moment from "moment";
import AttachmentDialog from "@/components/attachmentDialog.vue";
import PrintDom from "../../components/PrintDom.vue";
import ReportDialog from "../../components/ReportDialog.vue";
import PalletDialog from "../../components/palletDialog.vue";
const DIALOG_WITH_MENU = "DialogWithMenu";
const DIALOG_JUST_FORM = "DialogJustForm";
const DIALOG_CARPAYLOAD = "DialogCarPayload";
export default {
name: "ListViewWithHead",
components: {
BaseSearchForm,
BaseListTable,
DialogWithMenu,
DialogJustForm,
DialogCarPayload,
DialogUpload,
Overlay,
AttachmentDialog,
PrintDom,
ReportDialog,
PalletDialog,
},
props: {
navigator: {
type: Boolean,
default: true,
},
tableConfig: {
type: Object,
default: () => ({
/** 列配置, 即 props **/ column: [],
/** 表格整体配置 */ table: undefined,
}),
},
headConfig: {
type: Object,
default: () => ({}),
},
/** 请求page接口的时候有些字段是必填的没有会报500把相关字段名传入这个prop: */
listQueryExtra: {
type: Array,
default: () => ["key"],
},
attachListQueryExtra: {
// 新增时,附带 listQueryExtra 里的哪些键和对应值
type: String,
default: "",
},
initDataWhenLoad: { type: Boolean, default: true },
/** dialog configs 或许可以从 tableConfig 计算出来 computed... */
dialogConfigs: {
type: Object,
default: () => null,
},
carPayloadDialogConfigs: {
type: Object,
default: () => null,
},
triggerUpdate: {
type: String,
default: "",
},
},
computed: {
dialogType() {
return this.dialogConfigs.menu ? DIALOG_WITH_MENU : DIALOG_JUST_FORM;
},
},
activated() {
this.refreshLayoutKey = this.layoutTable();
},
watch: {
page: (val) => {
console.log("page changed:", val);
},
size: (val) => {
console.log("size changed:", val);
},
triggerUpdate(val, oldVal) {
if (val && val !== oldVal) {
// get list
this.page = 1;
this.size =
"defaultPageSize" in this.tableConfig.column ? this.tableConfig.column.defaultPageSize : 20;
this.getList();
}
},
},
data() {
return {
DIALOG_WITH_MENU,
DIALOG_JUST_FORM,
DIALOG_CARPAYLOAD,
dialogVisible: false,
carPayloadDialogVisible: false,
topBtnConfig: null,
totalPage: 0,
page: 1,
size: 20, // 默认20
dataList: [],
tableLoading: false,
refreshLayoutKey: null,
uploadDialogVisible: false,
overlayVisible: false,
cachedSearchCondition: {},
needAttachmentDialog: false,
tableSelectedIds: [],
printDOMmount: false,
queryParams: {},
carReportDialogVisible: false,
palletDialogVisible: false,
};
},
inject: ["urls"],
mounted() {
// 更新页面默认 size
const size =
"defaultPageSize" in this.tableConfig.column ? this.tableConfig.column.defaultPageSize : 20;
this.size = size;
// 如果设置了 listQueryExtra就合并到 queryParams
if (this.listQueryExtra && Array.isArray(this.listQueryExtra)) {
this.listQueryExtra.map((item) => {
if (typeof item === "string") this.$set(this.queryParams, item, "");
else if (typeof item === "object") {
Object.keys(item).forEach((key) => {
this.$set(this.queryParams, key, item[key]);
});
}
});
}
console.log("this.queryParams is: ", JSON.stringify(this.queryParams));
this.initDataWhenLoad && this.getList();
},
methods: {
/** 获取 列表数据 */
getList(queryParams) {
this.tableLoading = true;
const params = queryParams
? { ...queryParams, page: this.page, limit: this.size }
: {
page: this.page,
limit: this.size,
};
// this.dataList = [{}];
// this.tableLoading = false;
// return;
this.$http[this.urls.pageIsPostApi ? "post" : "get"](
this.urls.page,
this.urls.pageIsPostApi
? {
...this.queryParams,
...params,
}
: {
params: {
...this.queryParams,
...params,
},
}
)
.then(({ data: res }) => {
console.log("[http response] res is: ", res);
if (res.code === 0) {
// page 场景:
if ("list" in res.data) {
/** 破碎记录的特殊需求:数据要结合单位 material + materialUnitDictValue */
if ("attachDictValue" in this.tableConfig.column) {
this.dataList = res.data.list.map((row) => {
this.tableConfig.column.attachDictValue(row, "unit", "qty", "materialUnitDictValue");
return row;
});
} else this.dataList = res.data.list;
this.totalPage = res.data.total;
} else if (Array.isArray(res.data)) {
this.dataList = res.data;
} else {
this.dataList.splice(0);
this.totalPage = 0;
}
} else {
this.$message({
message: `${res.code}: ${res.msg}`,
type: "error",
duration: 2000,
});
}
this.tableLoading = false;
})
.catch((err) => {
this.$message({
message: `${err}`,
type: "error",
duration: 2000,
});
this.tableLoading = false;
});
// }
},
layoutTable() {
return Math.random();
},
handleTableSelect(ids) {
this.tableSelectedIds = [...ids];
},
/** 处理 表格操作 */
handleOperate({ type, data }) {
console.log("payload", type, data);
// 编辑、删除、跳转路由、打开弹窗动态component都可以在配置里加上 url
// payload: { type: string, data: string | number | object }
switch (type) {
case "delete": {
// 找到删除的 prompt 字段
const deleteConfig = data.head?.options?.find((item) => item.name === "delete");
let promptName = data.name ?? data.id;
if (deleteConfig && "promptField" in deleteConfig) {
promptName = data[deleteConfig.promptField];
}
let hintMsg = `确定要删除记录 "${promptName}" 吗?`;
if (promptName == data.id) {
// 如果 promptName 计算出来是 data.id 就以'该记录'代称
hintMsg = "确定删除该记录?";
}
let currenPageListLength = this.dataList.length;
// 确认是否删除
return this.$confirm(hintMsg, "提示", {
confirmButtonText: "确认",
cancelButtonText: "我再想想",
type: "warning",
})
.then(() => {
// this.$http.delete(this.urls.base + `/${data}`).then((res) => {
this.$http({
url: this.urls.base,
method: "DELETE",
// data: data.id,
data: [`${data.id}`],
// headers: {
// "Content-Type": "application/json"
// }
}).then(({ data: res }) => {
if (res.code === 0) {
this.$message.success("删除成功!");
// this.page = 1;
// this.size =
// "defaultPageSize" in this.tableConfig.column ? this.tableConfig.column.defaultPageSize : 20;
if (currenPageListLength == 1) this.page = this.page > 1 ? this.page - 1 : 1;
this.getList();
} else {
this.$message({
message: `${res.code}: ${res.msg}`,
type: "error",
duration: 1500,
});
}
});
})
.catch((err) => {});
}
case "edit": {
console.log("[edit] ", data);
this.openDialog(data); /** data is ==> id */
break;
}
case "view":
case "view-detail-action": {
this.openDialog(data, true);
break;
}
case "toggle-attachment-dialog": {
// alert("查看附件");
this.needAttachmentDialog = true;
setTimeout(() => {
this.$refs["attachmentDialog"].init(data);
}, 300);
break;
}
case "view-blender-batch-details": {
this.$router.push({
name: "pms-blenderBatchDetails",
query: {
batchId: data,
},
});
break;
}
case "view-car-record": {
// 查看窑车历史记录 - from 托盘页面
this.openDialog(data, true);
break;
}
case "status": {
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"];
// 更改状态,更改状态需要 id 和 code 然后是 状态 enabled
this.$http.put(this.urls.base, queryCondition).then(({ data: res }) => {
if (res.code === 0) {
// do nothing
} else {
this.$message({
message: `${res.code}: ${res.msg}`,
type: "error",
duration: 1500,
});
}
});
break;
}
case "view-attachment": {
this.openDialog(data, false, { key: "attachment" });
break;
}
case "view-attachment-justform-version": {
console.log(data);
break;
}
case "view-recipe": {
this.openDialog(data, true, { key: "attr" });
break;
}
case "to-bom-detail": {
console.log("to-bom-detail", data);
// 查看配方详情
return this.$router.push({
name: "pms-bomDetails",
query: {
code: data.code,
},
});
}
case "copy": {
let shouldShowOverlay = false;
this.$confirm("是否复制该记录?", "提示", {
confirmButtonText: "确定",
cancelButtonText: "取消",
type: "warning",
})
.then(() => {
//
let payload = "";
console.log("copying...", type, data);
if (typeof data === "object") {
const head = data.head;
const copyOpt =
("options" in head &&
Array.isArray(head.options) &&
head.options.find((item) => item.name === "copy")) ||
null;
if (copyOpt && "showOverlay" in copyOpt && copyOpt.showOverlay) {
this.overlayVisible = true;
shouldShowOverlay = true;
payload = data.id;
}
} else payload = data;
return this.$http.post(this.urls.copyUrl, payload, {
headers: {
"Content-Type": "application/json",
},
});
})
.then(({ data: res }) => {
if (res.code === 0) {
this.$message({
message: "复制成功!",
type: "success",
duration: 1500,
});
this.getList();
} else {
this.$message({
message: `${res.code}: ${res.msg}`,
type: "error",
duration: 1500,
});
}
if (shouldShowOverlay) this.overlayVisible = false;
})
.catch((errMsg) => {
errMsg !== "cancel" &&
this.$message({
message: errMsg,
type: "error",
duration: 1500,
});
if (shouldShowOverlay) this.overlayVisible = false;
});
break;
}
case "change-category": {
return this.$http.put(this.urls.base, data).then(({ data: res }) => {
if (res.code === 0) {
this.$message({
message: "修改成功",
type: "success",
duration: 1500,
onClose: () => {
this.getList();
},
});
} else {
this.$message({
message: `${res.code}: ${res.msg}`,
type: "error",
duration: 1500,
});
}
});
}
case "preview": {
console.log("[PREVIEW] data", data);
// report preview
return this.$router.push({
name: "pms-reportPreview",
query: {
name: data.name,
},
});
}
case "design": {
console.log("[DESIGN] data", data);
// report design
return this.$router.push({
name: "pms-reportDesign",
query: {
name: data.name,
},
});
}
case "detach": {
return this.$confirm("是否下发?", "提示", {
confirmButtonText: "确定",
cancelButtonText: "取消",
type: "warning",
})
.then(() => {
this.$http
.post(this.urls.detach, data /* { id: data } */, {
headers: { "Content-Type": "application/json" },
})
.then(({ data: res }) => {
if (res.code === 0) {
this.$message({
message: "下发成功",
type: "success",
duration: 1500,
onClose: () => {
this.getList();
},
});
} else {
this.$message({
message: `${res.code}: ${res.msg}`,
type: "error",
duration: 1500,
});
}
});
})
.catch(() => {
this.$message({
type: "warning",
message: "已取消下发",
});
});
}
case "to-car-history": {
return this.$router.push({
name: "pms-carHistory",
query: {
code: data.code,
},
});
}
case "to-car-payload": {
// open dialog instead of redirect to a new page
this.openCarPayloadDialog(data);
break;
}
case "sync": {
return this.$confirm(`是否开始同步`, "提示", {
confirmButtonText: "同步",
cancelButtonText: "我再想想",
type: "warning",
}).then(() => {
let shouldShowOverlay = false;
let payload = "";
// console.log("sync...", type, data);
if (typeof data === "object") {
const head = data.head;
const syncOpt =
("options" in head &&
Array.isArray(head.options) &&
head.options.find((item) => item.name === "sync")) ||
null;
if (syncOpt && "showOverlay" in syncOpt && syncOpt.showOverlay) {
this.overlayVisible = true;
shouldShowOverlay = true;
payload = data.id;
}
} else payload = data;
this.$message({
message: "正在发起同步...",
type: "success",
});
// 同步单个料仓数据
this.$http
.post(this.urls.syncSingleUrl, payload, {
headers: {
"Content-Type": "application/json",
},
})
.then(({ data: res }) => {
this.$message({
message: res.msg,
type: res.code === 0 ? "success" : "error",
});
this.getList();
if (shouldShowOverlay) this.overlayVisible = false;
});
});
}
case "print": {
return this.$confirm("开始打印么", "提示", {
confirmButtonText: "确认",
cancelButtonText: "我再想想",
type: "warning",
})
.then(this.printOnce.bind(null, data))
.catch((err) => {
// console.log("cancel ", err);
});
}
}
},
openCarPayloadDialog(id) {
this.carPayloadDialogVisible = true;
this.$nextTick(() => {
this.$refs["car-payload-dialog"].init(id);
});
},
handleBtnClick({ btnName, payload }) {
console.log("[search] form handleBtnClick", btnName, payload);
switch (btnName) {
case "批量同步":
this.overlayVisible = true;
this.$http.post(this.urls.syncUrl, this.tableSelectedIds).then(({ data: res }) => {
this.$message({ message: res.msg, type: res.code === 0 ? "success" : "error" });
res.code == 0 && this.getList();
this.overlayVisible = false;
});
break;
case "新增":
this.openDialog();
break;
case "导入":
this.openUploadDialog();
break;
case "导出":
this.$http({
method: "post",
url: this.urls.export,
data: { page: this.page },
responseType: "blob",
}).then((res) => {
// console.log("导出", res);
const filename = res.headers['content-disposition'].split('filename=')[1];
const blob = new Blob([res.data]);
/** 通知 */
this.$notify({
title: "成功",
message: "开始下载",
type: "success",
duration: 1200,
});
if ("download" in document.createElement("a")) {
const alink = document.createElement("a");
alink.download = filename;
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 "手动添加": {
this.openDialog();
return;
}
case "查询": {
const params = Object.assign({}, payload);
if ("timerange" in params) {
if (!!params.timerange) {
const [startTime, endTime] = params["timerange"];
params.startTime = moment(startTime).format("YYYY-MM-DDTHH:mm:ss");
params.endTime = moment(endTime).format("YYYY-MM-DDTHH:mm:ss");
} else {
params.startTime = null;
params.endTime = null;
}
delete params.timerange;
}
// console.log(
// "查询 params",
// JSON.stringify({
// // ...this.queryParams,
// ...params,
// })
// );
this.queryParams = {
...this.queryParams,
...params,
};
this.getList();
break;
}
case "同步":
case "全部同步":
this.$confirm("是否同步数据?", "提示", {
confirmButtonText: "确定",
cancelButtonText: "取消",
type: "warning",
}).then(() => {
this.overlayVisible = true;
this.$http
.post(this.urls.syncUrl)
.then(({ data: res }) => {
console.log("同步", res);
this.$message({ message: res.msg, type: res.code === 0 ? "success" : "error" });
this.getList();
this.overlayVisible = false;
})
.catch((err) => {
this.overlayVisible = false;
});
});
break;
case "打印":
if (this.tableSelectedIds.length === 0) {
return this.$message({
message: "请先选择要打印的项",
type: "warning",
duration: 1500,
});
}
return this.$confirm("开始打印么", "提示", {
confirmButtonText: "确认",
cancelButtonText: "我再想想",
type: "warning",
})
.then(() => {
console.log("打印如下这些 ids:", this.tableSelectedIds);
// this.tableSelectedIds.reduce(async (id, _) => {
// await this.printOnce(id);
// })
this.tableSelectedIds.forEach(async (id) => {
await this.printOnce(id);
});
})
.catch((err) => {
this.$message.error(`批量打印出错: ${err}`);
});
case "报工":
console.log("报工ids:", this.tableSelectedIds);
this.carReportDialogVisible = true;
this.$nextTick(() => {
this.$refs["car-report-dialog"].init();
});
break;
case "生成托盘":
if (this.tableSelectedIds.length > 1) {
return this.$message({
message: "只能选择一项",
type: "warning",
duration: 1500,
});
}
// // 尾托检测 - 由后端限制
// if (this.tableSelectedIds.length == 1 && this.tableSelectedIds[0].typeDictValue != "2") {
// return this.$message({
// message: "只能选择尾托",
// type: "warning",
// duration: 1500,
// });
// }
this.palletDialogVisible = true;
this.$nextTick(() => {
this.$refs["pallet-dialog"].init();
});
break;
}
},
/** 打印一次 */
printOnce(id) {
return new Promise((resolve) => {
this.printDOMmount = true;
this.$nextTick(async () => {
console.log("[Print] 打印项:", id);
await this.$refs["print"].print(id);
resolve();
});
});
},
/** 导航器的操作 */
handleSizeChange(val) {
// val 是新值
this.page = 1;
this.size = val;
this.getList();
},
handlePageChange(val) {
// val 是新值
this.getList();
},
/** 打开对话框 */
openDialog(row_id, detail_mode, tag_info) {
this.dialogVisible = true;
let extraParams = null;
if (this.attachListQueryExtra && this.listQueryExtra.length) {
this.listQueryExtra.forEach((item) => {
let found = item[this.attachListQueryExtra];
if (found !== null && found !== undefined) extraParams = item;
});
}
this.$nextTick(() => {
console.log(`[edit-dialog] extraParams: ${extraParams}`);
this.$refs["edit-dialog"].init(/** some args... */ row_id, detail_mode, tag_info, extraParams);
});
},
openUploadDialog() {
this.uploadDialogVisible = true;
this.$nextTick(() => {
this.$refs["upload-dialog"].init();
});
},
},
};
</script>
<style scoped>
.list-view-with-head {
background: white;
/* height: 100%; */
min-height: inherit;
border-radius: 6px;
padding: 16px;
box-shadow: 0 0 1.125px 0.125px rgba(0, 0, 0, 0.125);
}
</style>