Files
cashier-web/src/views/product/index.vue
2026-01-30 16:01:44 +08:00

463 lines
15 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="app-container">
<!-- 列表 -->
<!-- 搜索 -->
<page-search ref="searchRef" :search-config="searchConfig" @query-click="newHandleQueryClick"
@reset-click="handleResetClick2" />
<!-- 顶部数据 -->
<Statistics :data="gongjiData"></Statistics>
<!-- 列表 -->
<page-content ref="contentRef" :content-config="contentConfig" @add-click="handleAddClick"
@edit-click="handleEditClick" @export-click="handleExportClick" @search-click="handleSearchClick"
@toolbar-click="handleToolbarClick" @operat-click="handleOperatClick" @filter-change="handleFilterChange">
<!-- <template #status="scope">
<el-tag :type="scope.row[scope.prop] == 1 ? 'success' : 'info'">
{{ scope.row[scope.prop] == 1 ? "启用" : "禁用" }}
</el-tag>
</template> -->
<template #type="scope">
{{ typeFilter(scope.row[scope.prop]) }}
</template>
<template #gender="scope">
<DictLabel v-model="scope.row[scope.prop]" code="gender" />
</template>
<template #shangjia="scope">
<el-switch v-model="scope.row[scope.prop]" :active-value="1" :inactive-value="0"
@click="handleSwitchChange(scope.row)"></el-switch>
</template>
<template #isStock="scope">
<el-switch disabled v-model="scope.row[scope.prop]" :active-value="1" :inactive-value="0"></el-switch>
</template>
<template #kucunedit="scope">
<template v-if="scope.row.type != null">
{{ scope.row.stockNumber }}
<el-icon @click="kucunedit(scope.row)" style="cursor: pointer; color: #4080ff">
<EditPen />
</el-icon>
</template>
</template>
<template #tuikuantuihui="scope">
<el-switch v-if="!scope.row.productId" v-model="scope.row[scope.prop]" :active-value="1" :inactive-value="0"
@click="handleSwitchhaocai(scope.row)"></el-switch>
</template>
<template #sellOut="scope">
<el-switch v-model="scope.row[scope.prop]" :active-value="1" :inactive-value="0"
@click="handleSwitchChangeTwo(scope.row)"></el-switch>
</template>
<template #mobile="scope">
<el-text>{{ scope.row[scope.prop] }}</el-text>
<copy-button v-if="scope.row[scope.prop]" :text="scope.row[scope.prop]" style="margin-left: 2px" />
</template>
<template #consumables="scope">
<template v-if="scope.row.type != null">
<span style="color: #4080ff" v-if="scope.row.consName">
{{ scope.row.consName }}
</span>
<span v-else>绑定</span>
<el-icon @click="editOpen(scope.row)" style="cursor: pointer; color: #4080ff">
<EditPen />
</el-icon>
</template>
</template>
</page-content>
<!-- 新增 -->
<page-modal ref="addModalRef" :modal-config="addModalConfig" @submit-click="handleSubmitClick">
<template #gender="scope">
<Dict v-model="scope.formData[scope.prop]" code="gender" />
</template>
</page-modal>
<!-- 编辑 -->
<page-modal ref="editModalRef" :modal-config="editModalConfig" @submit-click="handleSubmitClick">
<template #gender="scope">
<Dict v-model="scope.formData[scope.prop]" code="gender" v-bind="scope.attrs" />
</template>
</page-modal>
<!-- 库存预警设置 -->
<MyDialog ref="myDialogRef" @confirm="confirm" title="修改库存预警">
<el-form :model="form">
<el-form-item label="库存预警" label-width="">
<el-input-number v-model="form.warnLine" label="描述文字"></el-input-number>
</el-form-item>
</el-form>
</MyDialog>
<!-- 报损 -->
<MyDialog ref="myDialogRefbaosun" @confirm="confirmbaosun" title="报损">
<el-form :model="form">
<el-form-item label="报损数量" label-width="">
<el-input-number v-model="datas.number" :min="1" label="描述文字"></el-input-number>
</el-form-item>
<el-form-item label="报损照片" label-width="">
<MultiImageUpload v-model="datas.images" />
</el-form-item>
<el-form-item label="备注" label-width="">
<el-input v-model="datas.remark" type="textarea" />
</el-form-item>
</el-form>
</MyDialog>
<!-- 耗材绑定 -->
<MyDialog ref="myDialogRefhaocai" @confirm="confirmhaocai" width="50%" title="耗材绑定">
<el-row>
<el-col :span="12">
<el-form-item label="商品名">
{{ haocaiData.name }}
</el-form-item>
</el-col>
<el-col :span="12">
<!-- <el-form-item label="退款退回库存">
<el-switch v-model="haocaiData.isRefundStock" :active-value="1" :inactive-value="0"
@click="handleSwitchhaocai(haocaiData.isRefundStock)"></el-switch>
</el-form-item> -->
</el-col>
</el-row>
<el-table :data="haocaiData.consList" border>
<el-table-column label="序号" type="index" width="60"></el-table-column>
<el-table-column label="耗材名称" prop="consInfoId">
<template v-slot="scope">
<el-select v-model="scope.row.consInfoId" reserve-keyword placeholder="请输入关键词"
@change="selectionChange($event, scope.row)">
<el-option v-for="item in options" :key="item.id" :label="item.conName" :value="item.id"></el-option>
</el-select>
<!-- <div class="tips" v-if="scope.row.stockNumber">库存{{ scope.row.stockNumber }}</div> -->
</template>
</el-table-column>
<el-table-column label="单位" prop="conUnit">
<template v-slot="scope">
<el-input v-model="scope.row.conUnit" readonly disabled placeholder="请选择耗材"></el-input>
<!-- <el-select v-model="scope.row.conUnit" reserve-keyword placeholder="请输入关键词">
<el-option
v-for="item in returnConUnits(scope.row.consInfoId)"
:key="item"
:label="item"
:value="item"
></el-option>
</el-select> -->
</template>
</el-table-column>
<el-table-column label="使用数量" prop="surplusStock" min-width="150px">
<template v-slot="scope">
<el-input-number v-model="scope.row.surplusStock" :min="0" />
</template>
</el-table-column>
<el-table-column label="操作" width="100">
<template v-slot="scope">
<div class="table_btn_wrap">
<div class="btn sub" v-if="haocaiData.consList.length > 1"
@click="haocaiData.consList.splice(scope.$index, 1)">
<el-icon>
<RemoveFilled />
</el-icon>
</div>
<div class="btn add" v-if="scope.$index == haocaiData.consList.length - 1" @click="createItem(scope.row)">
<el-icon>
<CirclePlusFilled />
</el-icon>
</div>
</div>
</template>
</el-table-column>
</el-table>
</MyDialog>
<!-- 库存修改 -->
<MyDialog ref="myDialogRefkucun" @confirm="confirmkucun" width="30%" title="库存修改">
<el-input-number v-model="kucundata.stockNumbers" :min="0" />
</MyDialog>
</div>
</template>
<script setup lang="ts">
import UserAPI from "@/api/product/index";
import { useRouter } from "vue-router";
import type { IObject, IOperatData } from "@/components/CURD/types";
import usePage from "@/components/CURD/usePage";
import { isSyncStatus, downloadFile } from "@/utils/index";
import addModalConfig from "./indexconfig/add";
import contentConfig from "./indexconfig/content";
import MultiImageUpload from "@/components/Upload/MultiImageUpload.vue";
import contentConfig2 from "./indexconfig/content2";
import editModalConfig from "./indexconfig/edit";
import searchConfig from "./indexconfig/search";
import MyDialog from "@/components/mycomponents/myDialog.vue";
import Statistics from "./indexconfig/statistics.vue";
const {
searchRef,
contentRef,
addModalRef,
editModalRef,
handleQueryClick,
handleResetClick,
// handleEditClick,
handleSubmitClick,
// handleExportClick,
handleSearchClick,
handleFilterChange,
} = usePage();
const router = useRouter();
let gongjiData = ref({});
const myDialogRef = ref(null);
const route = useRoute();
const myDialogRefbaosun = ref(null);
const myDialogRefhaocai = ref(null);
const myDialogRefkucun = ref(null);
let haocaiData = ref({});
let options = ref([]);
//选择耗材单位
const returnConUnits = (consInfoId) => {
const arr = [];
const item = options.value.find((item) => item.id === consInfoId);
if (item) {
if (item.conUnit) {
arr.push(item.conUnit);
}
if (item.conUnitTwo) {
arr.push(item.conUnitTwo);
}
}
return arr;
};
let kucundata = ref(0);
const form = reactive({
warnLine: "",
});
let datas = reactive({
number: 0,
remark: "",
images: [],
productId: null, // Added productId property
});
if (isSyncStatus()) {
contentConfig.toolbar[0].hidden = true;
contentConfig.toolbar[1].hidden = false;
contentConfig.cols[contentConfig.cols.length - 1].operat[2].hidden = true;
} else {
contentConfig.toolbar[0].hidden = false;
contentConfig.toolbar[1].hidden = true;
contentConfig.cols[contentConfig.cols.length - 1].operat[2].hidden = false;
}
onMounted(async () => {
console.log(route.query);
if (route.query.id) {
contentRef.value?.fetchPageData({ id: route.query.id });
}
// 获取耗材列表
gethaocaiList();
const res = await UserAPI.getPage()
form.warnLine = res.warnLine || ''
// console.log('contentRef.value===', res);
});
function newHandleQueryClick(e: IObject | undefined) {
const filterParams = contentRef.value?.getFilterParams();
contentRef.value?.fetchPageData({ ...e, ...filterParams }, true);
getTongji(e);
}
// 库存修改
function kucunedit(item) {
kucundata.value = item;
kucundata.value.stockNumbers = item.stockNumber;
myDialogRefkucun.value.open();
}
async function confirmkucun() {
let res = await UserAPI.modifyStock({
id: kucundata.value.id,
stockNumber: kucundata.value.stockNumbers,
});
kucundata.value.stockNumber = kucundata.value.stockNumbers;
ElMessage.success("成功");
myDialogRefkucun.value.close();
}
function editOpen(item: any) {
haocaiData.value = item;
console.log(item);
if (haocaiData.value.consList.length == 0) {
let items = {
productId: item.id,
consInfoId: "",
surplusStock: "0",
};
haocaiData.value.consList.push(items);
}
handleResetClick();
myDialogRefhaocai.value.open();
}
// 重置
function handleResetClick2(queryParams: IObject) {
const filterParams = contentRef.value?.getFilterParams();
contentRef.value?.fetchPageData({ ...queryParams, ...filterParams }, true);
getTongji(queryParams);
}
function getTongji(params: IObject | undefined) {
UserAPI.statistics(params).then((res) => {
gongjiData.value = res;
});
}
// 导出商品
async function handleExportClick() {
try {
const filterParams = searchRef.value?.getQueryParams();
const file = await UserAPI.exportProducts(filterParams);
downloadFile(file, "商品列表", "xlsx");
} catch (error) {
console.log(error);
}
}
// 新增
async function handleAddClick() {
router.push({ name: "addgoods" });
// addModalRef.value?.setModalVisible();
// 加载上级规格下拉数据源
// addModalConfig.formItems[2]!.attrs!.data = await UserAPI.getPage({ name: "" });
// 加载角色下拉数据源
}
// 生成新商品绑定耗材关系项
function createItem(val: IObject) {
let item = {
productId: val.productId,
consInfoId: "",
surplusStock: "",
};
haocaiData.value.consList.push(item);
}
// 上架
function handleSwitchChange(data: any) {
let obj = {
type: data.productId ? "sku" : "product",
id: data.id,
isSale: data.isSale,
};
UserAPI.onOff(obj);
}
// 售罄
function handleSwitchChangeTwo(data: any) {
let obj = {
type: data.specInfo ? "sku" : "product",
id: data.id,
isSoldOut: data.isSoldStock,
};
UserAPI.markIsSoldOut(obj);
}
function handleSwitchChangethree(data: any) {
let obj = {
type: data.type == "sku" ? "sku" : "product",
id: data.id,
isSoldOut: data.isSoldStock,
};
UserAPI.markIsSoldOut(obj);
}
// 退款退回
async function handleSwitchhaocai(row: IObject) {
let res = await UserAPI.refundToStock({ isReturn: row.isRefundStock, id: row.id });
ElMessage.success("成功");
handleResetClick();
// myDialogRefhaocai.value.close()
}
// 编辑
async function handleEditClick(row: IObject) {
try {
router.push({ name: "addgoods", query: { goods_id: row.id } });
} catch (error) {
ElMessage.error("没有编辑权限");
}
}
// 其他工具栏
async function handleToolbarClick(name: string) {
console.log(name);
if (name === "custom1") {
// ElMessage.success("点击了自定义1按钮");
myDialogRef.value.open();
}
if (name === "sync") {
//商品同步
let res = await UserAPI.sync();
ElMessage.success("操作成功,数据正在后台同步中...");
}
}
async function confirm() {
let res = await UserAPI.stockWarning(form.warnLine);
ElMessage.success("成功");
myDialogRef.value.close();
}
// 商品选择耗材
function selectionChange(e, row) {
let item = options.value.find((item) => item.id == e);
row.name = item.conName;
row.conUnit = item.conUnit;
}
async function confirmbaosun() {
let res = await UserAPI.reportDamage(datas);
ElMessage.success("成功");
myDialogRefbaosun.value.close();
contentRef.value?.fetchPageData();
}
async function confirmhaocai() {
let obj = {
consList: haocaiData.value.consList,
id: haocaiData.value.id,
};
let res = await UserAPI.bind(obj);
ElMessage.success("成功");
handleResetClick();
myDialogRefhaocai.value.close();
}
// 商品规格
function typeFilter(item: any) {
if (item == "single") {
return "单规格";
} else if (item == "sku") {
return "多规格";
} else if (item == "package") {
return "套餐商品";
} else if (item == "weight") {
return "称重商品";
} else if (item == "coupon") {
return "团购券";
}
}
// 其他操作列
async function handleOperatClick(data: IOperatData) {
datas.productId = data.row.id;
myDialogRefbaosun.value.open();
datas.number = 1;
datas.remark = "";
}
async function gethaocaiList() {
let res = await UserAPI.productcons({ id: route.query.id });
options.value = res.records;
}
</script>
<style scoped lang="scss">
.table_btn_wrap {
display: flex;
align-items: center;
gap: 16px;
.btn {
font-size: 26px;
&.sub {
color: #ff4d4f;
}
&.add {
color: #52c41a;
}
}
}
</style>