2021-03-15 20:53:32 +08:00

954 lines
28 KiB
Vue

<template>
<div class="app-container">
<el-form
:model="queryParams"
ref="queryForm"
:inline="true"
v-show="showSearch"
label-width="68px"
>
<el-form-item label="菜品名称" prop="name">
<el-input
v-model="queryParams.name"
placeholder="请输入菜品名称"
clearable
size="mini"
@keyup.enter.native="handleQuery"
/>
</el-form-item>
<el-form-item label="菜品种类" prop="dishClass">
<el-cascader
size="mini"
v-model="dishClassQueryParam"
:options="dishClassOptions"
:props="{ expandTrigger: 'hover' }"
:show-all-levels="true"
filterable
clearable
placeholder="请选择菜品种类"
></el-cascader>
</el-form-item>
<el-form-item label="菜品类型" prop="type">
<el-select
v-model="queryParams.type"
placeholder="请选择菜品类型"
clearable
size="mini"
>
<el-option
v-for="dict in typeOptions"
:key="dict.dictValue"
:label="dict.dictLabel"
:value="dict.dictValue"
/>
</el-select>
</el-form-item>
<el-form-item label="审核状态" prop="reviewStatus">
<el-select
v-model="queryParams.reviewStatus"
placeholder="请选择审核状态"
clearable
>
<el-option
v-for="dict in reviewStatusOptions"
:key="dict.dictValue"
:label="dict.dictLabel"
:value="dict.dictValue"
/>
</el-select>
</el-form-item>
<el-form-item>
<el-button
type="cyan"
icon="el-icon-search"
size="mini"
@click="handleQuery"
>搜索
</el-button>
<el-button icon="el-icon-refresh" size="mini" @click="resetQuery"
>重置
</el-button>
</el-form-item>
</el-form>
<el-row :gutter="10" class="mb8">
<el-col :span="1.5">
<el-button
type="primary"
icon="el-icon-plus"
size="mini"
@click="handleAdd"
v-hasPermi="['custom:dishes:add']"
>新增
</el-button>
</el-col>
<el-col :span="1.5">
<el-button
type="warning"
icon="el-icon-download"
size="mini"
@click="handleExport"
v-hasPermi="['custom:dishes:export']"
>导出
</el-button>
</el-col>
<right-toolbar
:showSearch.sync="showSearch"
@queryTable="getList"
></right-toolbar>
</el-row>
<el-table
v-loading="loading"
:data="dishesList"
@selection-change="handleSelectionChange"
>
<el-table-column label="审核状态" align="center" width="80">
<template slot-scope="scope">
<el-tag
:type="scope.row.reviewStatus === 'yes' ? 'success' : 'danger'"
disable-transitions
>
{{ scope.row.reviewStatus === "yes" ? "已审核" : "未审核" }}
</el-tag>
</template>
</el-table-column>
<el-table-column label="菜品名称" align="center" prop="name" />
<el-table-column label="菜品种类" align="center" prop="bigClass">
<template slot-scope="scope">
{{ dishClassFormat(scope.row) }}
</template>
</el-table-column>
<el-table-column label="菜品类型" align="center" prop="type">
<template slot-scope="scope">
<autohideinfo :data="typeFormat(scope.row)" />
</template>
</el-table-column>
<el-table-column label="包含食材" align="center">
<template slot-scope="scope">
<div v-for="igd in scope.row.igdList" :key="igd.id">
{{ igd.name }}
</div>
</template>
</el-table-column>
<el-table-column label="推荐人群" align="center">
<template slot-scope="scope">
<autohideinfo :data="scope.row.recTags" />
</template>
</el-table-column>
<el-table-column label="忌口人群" align="center">
<template slot-scope="scope">
<autohideinfo :data="scope.row.notRecTags" />
</template>
</el-table-column>
<el-table-column label="做法" align="center" prop="methods" />
<el-table-column
label="操作"
align="center"
class-name="small-padding fixed-width"
>
<template slot-scope="scope">
<el-button
size="mini"
type="text"
icon="el-icon-edit"
@click="handleUpdate(scope.row)"
v-hasPermi="['custom:dishes:edit']"
>修改
</el-button>
<el-button
size="mini"
type="text"
icon="el-icon-delete"
@click="handleDelete(scope.row)"
v-hasPermi="['custom:dishes:remove']"
>删除
</el-button>
</template>
</el-table-column>
</el-table>
<pagination
v-show="total > 0"
:total="total"
:page.sync="queryParams.pageNum"
:limit.sync="queryParams.pageSize"
@pagination="getList"
/>
<!-- 添加或修改菜品对话框 -->
<el-drawer
:title="title"
:visible.sync="open"
:wrapperClosable="false"
size="50%"
:close-on-press-escape="false"
>
<div class="drawer_content">
<el-row class="content_detail">
<el-form ref="form" :model="form" :rules="rules" label-width="80px">
<el-col :span="24">
<el-form-item label="菜品名称" prop="name">
<el-input v-model="form.name" placeholder="请输入菜品名称" />
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="菜品种类" prop="dishClass">
<el-cascader
filterable
v-model="form.dishClass"
:options="dishClassOptions"
:props="{ expandTrigger: 'hover' }"
placeholder="请选择菜品种类"
></el-cascader>
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="菜品类型" prop="type">
<el-select
v-model="form.type"
placeholder="请选择菜品类型"
multiple
>
<el-option
v-for="dict in typeOptions"
:key="dict.dictValue"
:label="dict.dictLabel"
:value="dict.dictValue"
></el-option>
</el-select>
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="是否主食" prop="isMain">
<el-radio-group v-model="form.isMain">
<el-radio :label="0">是</el-radio>
<el-radio :label="1">否</el-radio>
</el-radio-group>
</el-form-item>
</el-col>
<el-col :span="24">
<el-form-item label="食材" prop="ingIds">
<el-transfer
style="text-align: left; display: inline-block"
v-model="selIngIds"
size="mini"
filterable
:titles="['备选', '已选']"
:button-texts="['', '']"
:format="{
noChecked: '${total}',
hasChecked: '${checked}/${total}',
}"
@change="handleChange"
:data="ingDataList"
>
<el-select
class="transfer-footer"
slot="left-footer"
size="small"
filterable
v-model="ingType"
@change="handleOnTypeChange"
>
<el-option
v-for="dict in ingTypeOptions"
:key="dict.dictValue"
:label="dict.dictLabel"
:value="dict.dictValue"
/>
</el-select>
<div
class="transfer-footer"
slot="right-footer"
size="small"
/>
</el-transfer>
</el-form-item>
</el-col>
<el-col :span="24">
<el-form-item label="分量" prop="weight">
<el-table
:data="selTableData"
border
show-summary
size="mini"
:summary-method="getSummaries"
style="width: 100%"
>
<el-table-column prop="name" label="食材" align="center" />
<el-table-column label="通俗计量" align="center">
<template slot-scope="scope">
<span class="cus-unit">
<el-select size="mini" v-model="scope.row.cusWeight">
<el-option
v-for="dict in cusWeightOptions"
:key="dict.dictValue"
:label="dict.dictLabel"
:value="parseInt(dict.dictValue)"
/>
</el-select>
<el-select size="mini" v-model="scope.row.cusUnit">
<el-option
v-for="dict in cusUnitOptions"
:key="dict.dictValue"
:label="dict.dictLabel"
:value="parseInt(dict.dictValue)"
/>
</el-select>
</span>
</template>
</el-table-column>
<el-table-column prop="weight" label="重量(g)" align="center">
<template slot-scope="scope">
<el-input-number
class="weight"
v-model="scope.row.weight"
size="mini"
controls-position="right"
:min="0"
:step="5"
/>
</template>
</el-table-column>
<el-table-column
prop="proteinRatio"
label="蛋白质/100g"
align="center"
/>
<el-table-column
prop="fatRatio"
label="脂肪/100g"
align="center"
/>
<el-table-column
prop="carbonRatio"
label="碳水/100g"
align="center"
/>
<el-table-column label="热量" align="center">
<template slot-scope="scope">
{{
`${(
((scope.row.proteinRatio * scope.row.weight) / 100) *
4 +
((scope.row.fatRatio * scope.row.weight) / 100) * 9 +
((scope.row.carbonRatio * scope.row.weight) / 100) * 4
).toFixed(1)} kcal`
}}
</template>
</el-table-column>
</el-table>
</el-form-item>
</el-col>
<el-col :span="24">
<el-form-item label="推荐人群">
<el-tag
style="margin-right: 4px"
v-for="rec in selRec"
:key="rec"
type="success"
>
{{ rec }}
</el-tag>
</el-form-item>
</el-col>
<el-col :span="24">
<el-form-item label="忌口人群">
<el-tag
style="margin-right: 4px"
v-for="notRec in selNotRec"
:key="notRec"
type="danger"
>
{{ notRec }}
</el-tag>
</el-form-item>
</el-col>
<el-col :span="24">
<el-form-item label="审核状态" prop="reviewStatus">
<el-select
v-model="form.reviewStatus"
placeholder="请选择审核状态"
clearable
>
<el-option
v-for="dict in reviewStatusOptions"
:key="dict.dictValue"
:label="dict.dictLabel"
:value="dict.dictValue"
/>
</el-select>
</el-form-item>
</el-col>
<el-col :span="24">
<el-form-item label="做法" prop="methods">
<el-input
v-model="form.methods"
type="textarea"
placeholder="请输入内容"
rows="4"
/>
</el-form-item>
</el-col>
</el-form>
</el-row>
<div slot="footer" class="dialog-footer">
<el-button type="primary" @click="submitForm"> </el-button>
<el-button @click="cancel"> </el-button>
</div>
</div>
</el-drawer>
</div>
</template>
<script>
import {
addDishes,
delDishes,
exportDishes,
getDishes,
listDishes,
updateDishes,
} from "@/api/custom/dishes";
import { listAllIngredient } from "@/api/custom/ingredient";
import AutoHideInfo from "@/components/AutoHideInfo";
export default {
name: "Dishes",
components: {
autohideinfo: AutoHideInfo,
},
data() {
return {
// 遮罩层
loading: true,
// 选中数组
ids: [],
// 非单个禁用
single: true,
// 非多个禁用
multiple: true,
// 显示搜索条件
showSearch: true,
// 总条数
total: 0,
// 菜品表格数据
dishesList: [],
// 审核状态
reviewStatusOptions: [],
// 弹出层标题
title: "",
// 是否显示弹出层
open: false,
ingType: "1",
// 食材类别字典
ingTypeOptions: [],
// 远程数据缓存,预防新增的食材找不到
oriDataList: [],
// 备选食材列表
ingDataList: [],
// 选中的食材列表
selIngList: [],
//
selRec: [],
//
selNotRec: [],
// 选中的食材id
selIngIds: [],
// 选中的食材分量列表
selTableData: [],
// 菜品类别字典
typeOptions: [],
// 通俗单位
cusUnitOptions: [],
//
cusWeightOptions: [],
dishClassOptions: [],
dishClassBigOptions: [],
dishClassSmallOptions: [],
// 查询参数
queryParams: {
pageNum: 1,
pageSize: 10,
name: null,
type: null,
bigClass: null,
smallClass: null,
},
// 表单参数
form: {},
// 表单校验
rules: {},
//菜品种类查询种类
dishClassQueryParam: [],
};
},
created() {
this.getList();
this.getDicts("cus_dishes_type").then((response) => {
this.typeOptions = response.data;
});
this.getDicts("cus_ing_type").then((response) => {
this.ingTypeOptions = response.data;
});
this.getDicts("cus_cus_unit").then((response) => {
this.cusUnitOptions = response.data;
});
this.getDicts("cus_cus_weight").then((response) => {
this.cusWeightOptions = response.data;
});
this.getDicts("cus_review_status").then((response) => {
this.reviewStatusOptions = response.data;
});
this.getDicts("dish_class_big").then((response) => {
this.dishClassBigOptions = response.data;
this.getDicts("dish_class_small").then((res) => {
this.dishClassSmallOptions = res.data;
this.dealDishClassBigAndSmall();
});
});
},
methods: {
/** 查询菜品列表 */
getList() {
this.loading = true;
if (
this.dishClassQueryParam != null &&
this.dishClassQueryParam.length > 0
) {
this.queryParams.smallClass = this.dishClassQueryParam[1];
} else {
this.queryParams.smallClass = null;
}
listDishes(this.queryParams).then((response) => {
this.dishesList = response.rows.map((d) => {
const recTags = [],
notRecTags = [];
d.igdList.forEach((igd) => {
if (igd.rec) {
igd.rec.split(",").forEach((rec) => {
if (!recTags.includes(rec)) {
recTags.push(rec);
}
});
}
if (igd.notRec) {
igd.notRec.split(",").forEach((notRec) => {
if (!notRecTags.includes(notRec)) {
notRecTags.push(notRec);
}
});
}
});
return {
...d,
recTags,
notRecTags,
};
});
// console.log(this.dishesList);
this.total = response.total;
this.loading = false;
});
},
//处理菜品大类小类的关系
dealDishClassBigAndSmall() {
this.dishClassBigOptions.forEach((item, index) => {
this.dishClassOptions.push({
value: parseInt(item.dictValue),
label: item.dictLabel,
children: [],
});
if (index == this.dishClassBigOptions.length - 1) {
this.dishClassSmallOptions.forEach((smallClass, i) => {
if (smallClass.remark) {
this.dishClassOptions[
parseInt(smallClass.remark - 1)
].children.push({
value: parseInt(smallClass.dictValue),
label: smallClass.dictLabel,
});
}
});
}
});
},
// 菜品类型字典翻译
typeFormat(row, column) {
return !row.type
? ""
: row.type
.split(",")
.map((type) => this.selectDictLabel(this.typeOptions, type));
},
cusUnitFormat(row, column) {
return this.selectDictLabel(this.cusUnitOptions, row.type);
},
cusWeightFormat(row, column) {
return this.selectDictLabel(this.cusWeightOptions, row.cusWeight);
},
// 地域字典翻译
reviewStatusFormat(row, column) {
return this.selectDictLabel(this.reviewStatusOptions, row.area);
},
//菜品种类翻译
dishClassFormat(row) {
if (row.bigClass > 0 && row.smallClass > 0) {
let bigClassName = this.selectDictLabel(
this.dishClassBigOptions,
row.bigClass
);
let smallClassName = this.selectDictLabel(
this.dishClassSmallOptions,
row.smallClass
);
return bigClassName + "/" + smallClassName;
}
return "";
},
// 取消按钮
cancel() {
this.open = false;
this.reset();
},
// 表单重置
reset() {
this.form = {
id: null,
name: null,
type: [],
dishClass: [],
methods: null,
createBy: null,
createTime: null,
updateBy: null,
updateTime: null,
igdList: [],
isMain: 1,
};
this.selIngIds = [];
this.selIngList = [];
this.selTableData = [];
this.oriDataList = [];
this.selRec = [];
this.selNotRec = [];
this.ingType = "1";
this.resetForm("form");
},
/** 搜索按钮操作 */
handleQuery() {
this.queryParams.pageNum = 1;
this.getList();
},
/** 重置按钮操作 */
resetQuery() {
this.resetForm("queryForm");
this.dishClassQueryParam = [];
this.handleQuery();
},
// 多选框选中数据
handleSelectionChange(selection) {
this.ids = selection.map((item) => item.id);
this.single = selection.length !== 1;
this.multiple = !selection.length;
},
/** 新增按钮操作 */
handleAdd() {
this.reset();
listAllIngredient({ type: this.ingType }).then((response) => {
this.open = true;
this.title = "添加菜品";
this.oriDataList = response.rows;
this.ingDataList = this.oriDataList.map((obj) => ({
key: obj.id,
label: obj.name,
}));
});
},
/** 修改按钮操作 */
handleUpdate(row) {
this.reset();
const id = row.id || this.ids;
getDishes(id).then((response) => {
this.form = response.data;
this.form.dishClass = [this.form.bigClass, this.form.smallClass];
this.form.type = this.form.type ? this.form.type.split(",") : null;
this.form.igdList.forEach((obj) => {
this.selIngIds.push(obj.id);
this.selIngList.push({
key: obj.id,
label: obj.name,
});
this.selTableData.push(obj);
if (obj.rec) {
obj.rec.split(",").forEach((rec) => {
if (!this.selRec.includes(rec)) {
this.selRec.push(rec);
}
});
}
if (obj.notRec) {
obj.notRec.split(",").forEach((notRec) => {
if (!this.selNotRec.includes(notRec)) {
this.selNotRec.push(notRec);
}
});
}
});
listAllIngredient({ type: this.ingType }).then((res) => {
this.open = true;
this.title = "修改菜品";
this.oriDataList = res.rows.concat(this.form.igdList);
this.ingDataList = this.oriDataList.reduce((arr, cur) => {
if (!arr.some(({ key }) => key === cur.id)) {
arr.push({
key: cur.id,
label: cur.name,
});
}
return arr;
}, []);
});
});
},
/** 提交按钮 */
submitForm() {
this.$refs["form"].validate((valid) => {
if (valid) {
if (!this.selTableData.length) {
this.$message.error("食材不能为空");
return;
}
const data = JSON.parse(JSON.stringify(this.form));
data.igdList = this.selTableData;
data.type = data.type.join(",");
if (data.id != null) {
updateDishes(data).then((response) => {
if (response.code === 200) {
this.msgSuccess("修改成功");
this.open = false;
this.getList();
}
});
} else {
addDishes(data).then((response) => {
if (response.code === 200) {
this.msgSuccess("新增成功");
this.open = false;
this.getList();
}
});
}
}
});
},
/** 删除按钮操作 */
handleDelete(row) {
const ids = row.id || this.ids;
this.$confirm('是否确认删除菜品编号为"' + ids + '"的数据项?', "警告", {
confirmButtonText: "确定",
cancelButtonText: "取消",
type: "warning",
})
.then(function () {
return delDishes(ids);
})
.then(() => {
this.getList();
this.msgSuccess("删除成功");
})
.catch(function () {});
},
/** 导出按钮操作 */
handleExport() {
const queryParams = this.queryParams;
this.$confirm("是否确认导出所有菜品数据项?", "警告", {
confirmButtonText: "确定",
cancelButtonText: "取消",
type: "warning",
})
.then(function () {
return exportDishes(queryParams);
})
.then((response) => {
this.download(response.msg);
})
.catch(function () {});
},
handleChange(value, direction, movedKeys) {
// console.log({
// oriIgdList: this.oriDataList,
// selIgdList: this.form.igdList,
// ingDataList: this.ingDataList,
// value,
// ingType: this.ingType,
// });
const newTableData = [];
this.selRec = [];
this.selNotRec = [];
this.selIngList = value.map((id) => {
// 搜索table中的数据
let tmpTableObj = this.selTableData.find((obj) => obj.id === id);
if (tmpTableObj) {
newTableData.push(tmpTableObj);
} else {
// 搜索请求的缓存数据
tmpTableObj = this.oriDataList.find((obj) => obj.id === id);
if (tmpTableObj) {
newTableData.push({
...tmpTableObj,
weight: 100,
cusWeight: 1,
cusUnit: 1,
});
}
}
if (tmpTableObj) {
if (tmpTableObj.rec) {
tmpTableObj.rec.split(",").forEach((rec) => {
if (!this.selRec.includes(rec)) {
this.selRec.push(rec);
}
});
}
if (tmpTableObj.notRec) {
tmpTableObj.notRec.split(",").forEach((notRec) => {
if (!this.selNotRec.includes(notRec)) {
this.selNotRec.push(notRec);
}
});
}
}
const tarObj = this.ingDataList.find(({ key }) => key === id);
return tarObj;
});
this.selTableData = newTableData;
},
handleOnTypeChange(value) {
listAllIngredient({ type: value }).then((res) => {
this.oriDataList = res.rows.concat(this.form.igdList);
this.ingDataList = this.oriDataList.reduce((arr, cur) => {
if (!arr.some(({ key }) => key === cur.id)) {
arr.push({
key: cur.id,
label: cur.name,
});
}
return arr;
}, []);
});
},
getSummaries(param) {
const { columns, data } = param;
// console.log(data);
return columns.reduce(
(arr, cur, idx) => {
if (idx > 1) {
if (idx === 6) {
arr[6] = arr[3] * 4 + arr[4] * 9 + arr[5] * 4 + " kcal";
} else {
arr[idx] = data.reduce((acc, dAcc) => {
if (idx === 2) {
return acc + parseFloat(dAcc.weight);
}
return parseFloat(
(
acc +
(dAcc[cur.property] * parseFloat(dAcc.weight)) / 100
).toFixed(1)
);
}, 0);
}
}
return arr;
},
["合计"]
);
},
},
};
</script>
<style rel="stylesheet/scss" lang="scss">
#el-drawer__title {
& > span:focus {
outline: 0;
}
}
.el-transfer-panel__filter {
margin: 2px;
}
.el-transfer-panel__list.is-filterable {
padding-bottom: 28px;
}
.cus-unit {
display: inline-flex;
.el-input-number--mini {
width: 38px;
}
.el-input-number {
.el-input-number__decrease {
display: none;
}
.el-input-number__increase {
display: none;
}
.el-input {
width: 38px;
}
.el-input .el-input__inner {
padding: 0;
border-radius: 0;
border: unset;
border-bottom: 1px solid #dcdfe6;
}
}
.el-select {
.el-input__suffix {
display: none;
}
.el-input__inner {
padding: 0 4px;
/* border: unset; */
text-align: center;
}
}
}
.weight {
width: 70px;
.el-input .el-input__inner {
padding: 0 32px 0 4px;
}
}
.drawer_content {
height: 100%;
display: flex;
flex-direction: column;
.content_detail {
flex: 1 1 0;
padding: 12px;
overflow: auto;
}
.dialog-footer {
flex: 0 0 45px;
display: inline-flex;
align-items: center;
justify-content: flex-end;
padding: 0 12px;
}
}
</style>