Merge branch 'master' of https://gitea.zianxin.com/zax/biz-pc-cloud
This commit is contained in:
commit
719c2e3969
28 files changed
+3519
-1719
No files matched your search
@@ -0,0 +1,41 @@
|
|||||||
|
import request from "/@/utils/request"
|
||||||
|
|
||||||
|
export function fetchList(query?: Object) {
|
||||||
|
return request({
|
||||||
|
url: '/integrated/meetingDeskLayout/page',
|
||||||
|
method: 'get',
|
||||||
|
params: query
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
export function addObj(obj?: Object) {
|
||||||
|
return request({
|
||||||
|
url: '/integrated/meetingDeskLayout',
|
||||||
|
method: 'post',
|
||||||
|
data: obj
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getObj(id?: string) {
|
||||||
|
return request({
|
||||||
|
url: '/integrated/meetingDeskLayout/' + id,
|
||||||
|
method: 'get'
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
export function delObjs(ids?: Object) {
|
||||||
|
return request({
|
||||||
|
url: '/integrated/meetingDeskLayout',
|
||||||
|
method: 'delete',
|
||||||
|
data: ids
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
export function putObj(obj?: Object) {
|
||||||
|
return request({
|
||||||
|
url: '/integrated/meetingDeskLayout',
|
||||||
|
method: 'put',
|
||||||
|
data: obj
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
@@ -39,10 +39,10 @@ export function putObj(obj?: Object) {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
export function tree(obj?: Object) {
|
export function tree(params?: Object) {
|
||||||
return request({
|
return request({
|
||||||
url: '/supermarket/mallCategory/tree',
|
url: '/supermarket/mallCategory/tree',
|
||||||
method: 'get',
|
method: 'get',
|
||||||
data: obj
|
params: params
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@@ -39,3 +39,14 @@ export function putObj(obj?: Object) {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 商户下拉
|
||||||
|
*/
|
||||||
|
export function selectOption(query?: Object) {
|
||||||
|
return request({
|
||||||
|
url: '/supermarket/selectOption/merchant',
|
||||||
|
method: 'get',
|
||||||
|
params: query
|
||||||
|
})
|
||||||
|
}
|
||||||
@@ -0,0 +1,91 @@
|
|||||||
|
import request from "/@/utils/request"
|
||||||
|
|
||||||
|
// 分页查询绑定关系
|
||||||
|
export function fetchList(query?: Object) {
|
||||||
|
return request({
|
||||||
|
url: '/supermarket/mallMerchantUser/page',
|
||||||
|
method: 'get',
|
||||||
|
params: query
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取商户用户列表
|
||||||
|
export function getMerchantUsers(merchantId: string, query?: Object) {
|
||||||
|
return request({
|
||||||
|
url: `/supermarket/mallMerchantUser/merchant/${merchantId}/users`,
|
||||||
|
method: 'get',
|
||||||
|
params: query
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取用户商户信息
|
||||||
|
export function getUserMerchant(userId: string) {
|
||||||
|
return request({
|
||||||
|
url: `/supermarket/mallMerchantUser/user/${userId}/merchant`,
|
||||||
|
method: 'get'
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 单个用户绑定
|
||||||
|
export function bindUser(data: Object) {
|
||||||
|
return request({
|
||||||
|
url: '/supermarket/mallMerchantUser/bind',
|
||||||
|
method: 'post',
|
||||||
|
data: data
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 批量绑定用户
|
||||||
|
export function batchBindUsers(data: Object) {
|
||||||
|
return request({
|
||||||
|
url: '/supermarket/mallMerchantUser/batchBind',
|
||||||
|
method: 'post',
|
||||||
|
data: data
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 解绑单个用户
|
||||||
|
export function unbindUser(userId: string) {
|
||||||
|
return request({
|
||||||
|
url: `/supermarket/mallMerchantUser/unbind/${userId}`,
|
||||||
|
method: 'delete'
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 批量解绑用户
|
||||||
|
export function batchUnbindUsers(data: Object) {
|
||||||
|
return request({
|
||||||
|
url: '/supermarket/mallMerchantUser/batchUnbind',
|
||||||
|
method: 'delete',
|
||||||
|
data: data
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 更新用户角色
|
||||||
|
export function updateUserRole(data: Object) {
|
||||||
|
return request({
|
||||||
|
url: '/supermarket/mallMerchantUser/updateRole',
|
||||||
|
method: 'put',
|
||||||
|
data: data
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 更新绑定状态
|
||||||
|
export function updateBindStatus(data: Object) {
|
||||||
|
return request({
|
||||||
|
url: '/supermarket/mallMerchantUser/updateStatus',
|
||||||
|
method: 'put',
|
||||||
|
data: data
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取用户下拉列表
|
||||||
|
export function getUserSelectList(query?: Object) {
|
||||||
|
return request({
|
||||||
|
url: '/supermarket/mallMerchantUser/merchant/users',
|
||||||
|
method: 'get',
|
||||||
|
params: query
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -68,7 +68,7 @@ const props = withDefaults(
|
|||||||
const queryForm = reactive<any>({
|
const queryForm = reactive<any>({
|
||||||
name: "",
|
name: "",
|
||||||
current: 1,
|
current: 1,
|
||||||
size: 10,
|
size: 999999,
|
||||||
})
|
})
|
||||||
|
|
||||||
const state = reactive<any>({
|
const state = reactive<any>({
|
||||||
@@ -99,6 +99,7 @@ async function getOptions() {
|
|||||||
...queryForm,
|
...queryForm,
|
||||||
...props.apiParams,
|
...props.apiParams,
|
||||||
userIds: [currentUserId.value],
|
userIds: [currentUserId.value],
|
||||||
|
size: 999999,
|
||||||
}
|
}
|
||||||
|
|
||||||
const { data } = await invoiceManager.invoiceSelect(_pa)
|
const { data } = await invoiceManager.invoiceSelect(_pa)
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
<template>
|
<template>
|
||||||
<el-dialog :title="form.id ? '编辑' : '新增'" v-model="visible"
|
<el-dialog :title="form.id ? '编辑' : '新增'" v-model="visible"
|
||||||
:close-on-click-modal="false" draggable>
|
:close-on-click-modal="false" draggable>
|
||||||
<el-form ref="dataFormRef" :model="form" :rules="dataRules" formDialogRef label-width="90px" v-loading="loading">
|
<el-form ref="dataFormRef" :model="form" :rules="dataRules" label-width="90px" v-loading="loading">
|
||||||
<el-row :gutter="24">
|
<el-row :gutter="24">
|
||||||
<el-col :span="12" class="mb20">
|
<el-col :span="12" class="mb20">
|
||||||
<el-form-item label="姓名" prop="name">
|
<el-form-item label="姓名" prop="name">
|
||||||
@@ -15,11 +15,7 @@
|
|||||||
</el-form-item>
|
</el-form-item>
|
||||||
</el-col>
|
</el-col>
|
||||||
|
|
||||||
<el-col :span="12" class="mb20">
|
|
||||||
<el-form-item label="部门id" prop="deptId">
|
|
||||||
<el-input v-model="form.deptId" placeholder="请输入部门id"/>
|
|
||||||
</el-form-item>
|
|
||||||
</el-col>
|
|
||||||
|
|
||||||
<el-col :span="12" class="mb20">
|
<el-col :span="12" class="mb20">
|
||||||
<el-form-item label="照片" prop="picUrl">
|
<el-form-item label="照片" prop="picUrl">
|
||||||
@@ -39,6 +35,7 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts" name="CleanUserDialog">
|
<script setup lang="ts" name="CleanUserDialog">
|
||||||
|
import { ref, reactive, nextTick } from 'vue';
|
||||||
import { useDict } from '/src/hooks/dict';
|
import { useDict } from '/src/hooks/dict';
|
||||||
import { useMessage } from "/src/hooks/message";
|
import { useMessage } from "/src/hooks/message";
|
||||||
import { getObj, addObj, putObj } from '/src/api/integrated/cleanUser'
|
import { getObj, addObj, putObj } from '/src/api/integrated/cleanUser'
|
||||||
@@ -56,8 +53,8 @@ const form = reactive({
|
|||||||
id:'',
|
id:'',
|
||||||
name: '',
|
name: '',
|
||||||
phone: '',
|
phone: '',
|
||||||
deptId: '',
|
|
||||||
picUrl: '',
|
picUrl: '',
|
||||||
|
type: '1', // 保洁人员
|
||||||
});
|
});
|
||||||
|
|
||||||
// 定义校验规则
|
// 定义校验规则
|
||||||
|
|||||||
@@ -40,7 +40,6 @@
|
|||||||
<el-table-column type="index" label="#" width="40" />
|
<el-table-column type="index" label="#" width="40" />
|
||||||
<el-table-column prop="name" label="姓名" show-overflow-tooltip/>
|
<el-table-column prop="name" label="姓名" show-overflow-tooltip/>
|
||||||
<el-table-column prop="phone" label="手机号" show-overflow-tooltip/>
|
<el-table-column prop="phone" label="手机号" show-overflow-tooltip/>
|
||||||
<el-table-column prop="deptId" label="部门id" show-overflow-tooltip/>
|
|
||||||
<el-table-column prop="picUrl" label="照片" show-overflow-tooltip/>
|
<el-table-column prop="picUrl" label="照片" show-overflow-tooltip/>
|
||||||
<el-table-column label="操作" width="150">
|
<el-table-column label="操作" width="150">
|
||||||
<template #default="scope">
|
<template #default="scope">
|
||||||
@@ -60,6 +59,7 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts" name="systemCleanUser">
|
<script setup lang="ts" name="systemCleanUser">
|
||||||
|
import { ref, reactive, defineAsyncComponent } from 'vue';
|
||||||
import { BasicTableProps, useTable } from "/src/hooks/table";
|
import { BasicTableProps, useTable } from "/src/hooks/table";
|
||||||
import { fetchList, delObjs } from "/src/api/integrated/cleanUser";
|
import { fetchList, delObjs } from "/src/api/integrated/cleanUser";
|
||||||
import { useMessage, useMessageBox } from "/src/hooks/message";
|
import { useMessage, useMessageBox } from "/src/hooks/message";
|
||||||
@@ -79,8 +79,8 @@ const selectObjs = ref([]) as any
|
|||||||
const multiple = ref(true)
|
const multiple = ref(true)
|
||||||
|
|
||||||
const state: BasicTableProps = reactive<BasicTableProps>({
|
const state: BasicTableProps = reactive<BasicTableProps>({
|
||||||
queryForm: {},
|
queryForm: { type: '1' }, // 保洁人员
|
||||||
pageList: fetchList
|
pageList: (params: any) => fetchList({ ...params, type: '1' })
|
||||||
})
|
})
|
||||||
|
|
||||||
// table hook
|
// table hook
|
||||||
|
|||||||
+40
-42
@@ -4,68 +4,65 @@
|
|||||||
<el-form ref="dataFormRef" :model="form" :rules="dataRules" formDialogRef label-width="90px" v-loading="loading">
|
<el-form ref="dataFormRef" :model="form" :rules="dataRules" formDialogRef label-width="90px" v-loading="loading">
|
||||||
<el-row :gutter="24">
|
<el-row :gutter="24">
|
||||||
<el-col :span="12" class="mb20">
|
<el-col :span="12" class="mb20">
|
||||||
<el-form-item label="SPU ID" prop="productId">
|
<el-form-item label="摆放形式名称" prop="layoutName">
|
||||||
<el-input v-model="form.productId" placeholder="请输入SPU ID"/>
|
<el-input v-model="form.layoutName" placeholder="请输入摆放形式名称"/>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
</el-col>
|
</el-col>
|
||||||
|
|
||||||
<el-col :span="12" class="mb20">
|
<el-col :span="12" class="mb20">
|
||||||
<el-form-item label="SKU编码" prop="skuCode">
|
<el-form-item label="摆放形式编码" prop="layoutCode">
|
||||||
<el-input v-model="form.skuCode" placeholder="请输入SKU编码"/>
|
<el-input v-model="form.layoutCode" placeholder="请输入摆放形式编码"/>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
</el-col>
|
</el-col>
|
||||||
|
|
||||||
<el-col :span="12" class="mb20">
|
<el-col :span="12" class="mb20">
|
||||||
<el-form-item label="SKU名称(规格组合)" prop="skuName">
|
<el-form-item label="摆放形式描述" prop="description">
|
||||||
<el-input v-model="form.skuName" placeholder="请输入SKU名称(规格组合)"/>
|
<el-input v-model="form.description" placeholder="请输入摆放形式描述"/>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
</el-col>
|
</el-col>
|
||||||
|
|
||||||
<el-col :span="12" class="mb20">
|
<el-col :span="12" class="mb20">
|
||||||
<el-form-item label="售价" prop="price">
|
<el-form-item label="最小容纳人数" prop="capacityMin">
|
||||||
<el-input v-model="form.price" placeholder="请输入售价"/>
|
<el-input v-model="form.capacityMin" placeholder="请输入最小容纳人数"/>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
</el-col>
|
</el-col>
|
||||||
|
|
||||||
<el-col :span="12" class="mb20">
|
<el-col :span="12" class="mb20">
|
||||||
<el-form-item label="成本价" prop="costPrice">
|
<el-form-item label="最大容纳人数" prop="capacityMax">
|
||||||
<el-input v-model="form.costPrice" placeholder="请输入成本价"/>
|
<el-input v-model="form.capacityMax" placeholder="请输入最大容纳人数"/>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
</el-col>
|
</el-col>
|
||||||
|
|
||||||
<el-col :span="12" class="mb20">
|
<el-col :span="12" class="mb20">
|
||||||
<el-form-item label="库存" prop="stock">
|
<el-form-item label="摆放形式示意图" prop="layoutImage">
|
||||||
<el-input v-model="form.stock" placeholder="请输入库存"/>
|
<el-input v-model="form.layoutImage" placeholder="请输入摆放形式示意图"/>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
</el-col>
|
</el-col>
|
||||||
|
|
||||||
<el-col :span="12" class="mb20">
|
<el-col :span="12" class="mb20">
|
||||||
<el-form-item label="条码" prop="barcode">
|
<el-form-item label="布置所需时间(分钟)" prop="setupTime">
|
||||||
<el-input v-model="form.barcode" placeholder="请输入条码"/>
|
<el-input v-model="form.setupTime" placeholder="请输入布置所需时间(分钟)"/>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
</el-col>
|
</el-col>
|
||||||
|
|
||||||
<el-col :span="12" class="mb20">
|
<el-col :span="12" class="mb20">
|
||||||
<el-form-item label="重量(克)" prop="weightG">
|
<el-form-item label="是否可用" prop="isAvailable">
|
||||||
<el-input v-model="form.weightG" placeholder="请输入重量(克)"/>
|
<el-radio-group v-model="form.isAvailable">
|
||||||
|
<el-radio value="0">可用</el-radio>
|
||||||
|
<el-radio value="1">不可用</el-radio>
|
||||||
|
</el-radio-group>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
</el-col>
|
</el-col>
|
||||||
|
|
||||||
<el-col :span="12" class="mb20">
|
<el-col :span="12" class="mb20">
|
||||||
<el-form-item label="体积(立方厘米)" prop="volumeCm3">
|
<el-form-item label="排序" prop="sortOrder">
|
||||||
<el-input v-model="form.volumeCm3" placeholder="请输入体积(立方厘米)"/>
|
<el-input v-model="form.sortOrder" placeholder="请输入排序"/>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
</el-col>
|
</el-col>
|
||||||
|
|
||||||
<el-col :span="12" class="mb20">
|
<el-col :span="12" class="mb20">
|
||||||
<el-form-item label="状态(1启用 0停用)" prop="status">
|
<el-form-item label="备注" prop="remark">
|
||||||
<el-input v-model="form.status" placeholder="请输入状态(1启用 0停用)"/>
|
<el-input v-model="form.remark" placeholder="请输入备注"/>
|
||||||
</el-form-item>
|
|
||||||
</el-col>
|
|
||||||
|
|
||||||
<el-col :span="12" class="mb20">
|
|
||||||
<el-form-item label="部门ID" prop="deptId">
|
|
||||||
<el-input v-model="form.deptId" placeholder="请输入部门ID"/>
|
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
</el-col>
|
</el-col>
|
||||||
|
|
||||||
@@ -80,10 +77,10 @@
|
|||||||
</el-dialog>
|
</el-dialog>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts" name="MallProductSkuDialog">
|
<script setup lang="ts" name="MeetingDeskLayoutDialog">
|
||||||
import { useDict } from '/@/hooks/dict';
|
import { useDict } from '/@/hooks/dict';
|
||||||
import { useMessage } from "/@/hooks/message";
|
import { useMessage } from "/@/hooks/message";
|
||||||
import { getObj, addObj, putObj } from '/@/api/supermarket/mallProductSku'
|
import { getObj, addObj, putObj } from '/@/api/integrated/meetingDeskLayout'
|
||||||
import { rule } from '/@/utils/validate';
|
import { rule } from '/@/utils/validate';
|
||||||
const emit = defineEmits(['refresh']);
|
const emit = defineEmits(['refresh']);
|
||||||
|
|
||||||
@@ -92,25 +89,26 @@ const dataFormRef = ref();
|
|||||||
const visible = ref(false)
|
const visible = ref(false)
|
||||||
const loading = ref(false)
|
const loading = ref(false)
|
||||||
// 定义字典
|
// 定义字典
|
||||||
|
const { is_show } = useDict('is_show')
|
||||||
|
|
||||||
// 提交表单数据
|
// 提交表单数据
|
||||||
const form = reactive({
|
const form = reactive({
|
||||||
id:'',
|
id:'',
|
||||||
productId: '',
|
layoutName: '',
|
||||||
skuCode: '',
|
layoutCode: '',
|
||||||
skuName: '',
|
description: '',
|
||||||
price: '',
|
capacityMin: '',
|
||||||
costPrice: '',
|
capacityMax: '',
|
||||||
stock: '',
|
layoutImage: '',
|
||||||
barcode: '',
|
setupTime: '',
|
||||||
weightG: '',
|
isAvailable: '0', // 默认可用
|
||||||
volumeCm3: '',
|
sortOrder: '',
|
||||||
status: '',
|
remark: '',
|
||||||
deptId: '',
|
|
||||||
});
|
});
|
||||||
|
|
||||||
// 定义校验规则
|
// 定义校验规则
|
||||||
const dataRules = ref({
|
const dataRules = ref({
|
||||||
|
layoutName: [{required: true, message: '摆放形式名称不能为空', trigger: 'blur'}],
|
||||||
})
|
})
|
||||||
|
|
||||||
// 打开弹窗
|
// 打开弹窗
|
||||||
@@ -123,10 +121,10 @@ const openDialog = (id: string) => {
|
|||||||
dataFormRef.value?.resetFields();
|
dataFormRef.value?.resetFields();
|
||||||
});
|
});
|
||||||
|
|
||||||
// 获取mallProductSku信息
|
// 获取meetingDeskLayout信息
|
||||||
if (id) {
|
if (id) {
|
||||||
form.id = id
|
form.id = id
|
||||||
getmallProductSkuData(id)
|
getmeetingDeskLayoutData(id)
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -150,7 +148,7 @@ const onSubmit = async () => {
|
|||||||
|
|
||||||
|
|
||||||
// 初始化表单数据
|
// 初始化表单数据
|
||||||
const getmallProductSkuData = (id: string) => {
|
const getmeetingDeskLayoutData = (id: string) => {
|
||||||
// 获取数据
|
// 获取数据
|
||||||
loading.value = true
|
loading.value = true
|
||||||
getObj(id).then((res: any) => {
|
getObj(id).then((res: any) => {
|
||||||
+23
-19
@@ -4,14 +4,14 @@
|
|||||||
<el-row>
|
<el-row>
|
||||||
<div class="mb8" style="width: 100%">
|
<div class="mb8" style="width: 100%">
|
||||||
<el-button icon="folder-add" type="primary" class="ml10" @click="formDialogRef.openDialog()"
|
<el-button icon="folder-add" type="primary" class="ml10" @click="formDialogRef.openDialog()"
|
||||||
v-auth="'supermarket_mallProductSku_add'">
|
v-auth="'integrated_meetingDeskLayout_add'">
|
||||||
新 增
|
新 增
|
||||||
</el-button>
|
</el-button>
|
||||||
<el-button plain :disabled="multiple" icon="Delete" type="primary"
|
<el-button plain :disabled="multiple" icon="Delete" type="primary"
|
||||||
v-auth="'supermarket_mallProductSku_del'" @click="handleDelete(selectObjs)">
|
v-auth="'integrated_meetingDeskLayout_del'" @click="handleDelete(selectObjs)">
|
||||||
删除
|
删除
|
||||||
</el-button>
|
</el-button>
|
||||||
<right-toolbar v-model:showSearch="showSearch" :export="'supermarket_mallProductSku_export'"
|
<right-toolbar v-model:showSearch="showSearch" :export="'integrated_meetingDeskLayout_export'"
|
||||||
@exportExcel="exportExcel" class="ml10 mr20" style="float: right;"
|
@exportExcel="exportExcel" class="ml10 mr20" style="float: right;"
|
||||||
@queryTable="getDataList"></right-toolbar>
|
@queryTable="getDataList"></right-toolbar>
|
||||||
</div>
|
</div>
|
||||||
@@ -22,22 +22,25 @@
|
|||||||
@sort-change="sortChangeHandle">
|
@sort-change="sortChangeHandle">
|
||||||
<el-table-column type="selection" width="40" align="center" />
|
<el-table-column type="selection" width="40" align="center" />
|
||||||
<el-table-column type="index" label="#" width="40" />
|
<el-table-column type="index" label="#" width="40" />
|
||||||
<el-table-column prop="productId" label="SPU ID" show-overflow-tooltip/>
|
<el-table-column prop="layoutName" label="摆放形式名称" show-overflow-tooltip/>
|
||||||
<el-table-column prop="skuCode" label="SKU编码" show-overflow-tooltip/>
|
<el-table-column prop="layoutCode" label="摆放形式编码" show-overflow-tooltip/>
|
||||||
<el-table-column prop="skuName" label="SKU名称(规格组合)" show-overflow-tooltip/>
|
<el-table-column prop="description" label="摆放形式描述" show-overflow-tooltip/>
|
||||||
<el-table-column prop="price" label="售价" show-overflow-tooltip/>
|
<el-table-column prop="capacityMin" label="最小容纳人数" show-overflow-tooltip/>
|
||||||
<el-table-column prop="costPrice" label="成本价" show-overflow-tooltip/>
|
<el-table-column prop="capacityMax" label="最大容纳人数" show-overflow-tooltip/>
|
||||||
<el-table-column prop="stock" label="库存" show-overflow-tooltip/>
|
<el-table-column prop="layoutImage" label="摆放形式示意图" show-overflow-tooltip/>
|
||||||
<el-table-column prop="barcode" label="条码" show-overflow-tooltip/>
|
<el-table-column prop="setupTime" label="布置所需时间(分钟)" show-overflow-tooltip/>
|
||||||
<el-table-column prop="weightG" label="重量(克)" show-overflow-tooltip/>
|
<el-table-column prop="isAvailable" label="是否可用" show-overflow-tooltip>
|
||||||
<el-table-column prop="volumeCm3" label="体积(立方厘米)" show-overflow-tooltip/>
|
<template #default="scope">
|
||||||
<el-table-column prop="status" label="状态(1启用 0停用)" show-overflow-tooltip/>
|
<dict-tag :options="is_show" :value="scope.row.isAvailable"></dict-tag>
|
||||||
<el-table-column prop="deptId" label="部门ID" show-overflow-tooltip/>
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
<el-table-column prop="sortOrder" label="排序" show-overflow-tooltip/>
|
||||||
|
<el-table-column prop="remark" label="备注" show-overflow-tooltip/>
|
||||||
<el-table-column label="操作" width="150">
|
<el-table-column label="操作" width="150">
|
||||||
<template #default="scope">
|
<template #default="scope">
|
||||||
<el-button icon="edit-pen" text type="primary" v-auth="'supermarket_mallProductSku_edit'"
|
<el-button icon="edit-pen" text type="primary" v-auth="'integrated_meetingDeskLayout_edit'"
|
||||||
@click="formDialogRef.openDialog(scope.row.id)">编辑</el-button>
|
@click="formDialogRef.openDialog(scope.row.id)">编辑</el-button>
|
||||||
<el-button icon="delete" text type="primary" v-auth="'supermarket_mallProductSku_del'" @click="handleDelete([scope.row.id])">删除</el-button>
|
<el-button icon="delete" text type="primary" v-auth="'integrated_meetingDeskLayout_del'" @click="handleDelete([scope.row.id])">删除</el-button>
|
||||||
</template>
|
</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
</el-table>
|
</el-table>
|
||||||
@@ -50,9 +53,9 @@
|
|||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts" name="systemMallProductSku">
|
<script setup lang="ts" name="systemMeetingDeskLayout">
|
||||||
import { BasicTableProps, useTable } from "/@/hooks/table";
|
import { BasicTableProps, useTable } from "/@/hooks/table";
|
||||||
import { fetchList, delObjs } from "/@/api/supermarket/mallProductSku";
|
import { fetchList, delObjs } from "/@/api/integrated/meetingDeskLayout";
|
||||||
import { useMessage, useMessageBox } from "/@/hooks/message";
|
import { useMessage, useMessageBox } from "/@/hooks/message";
|
||||||
import { useDict } from '/@/hooks/dict';
|
import { useDict } from '/@/hooks/dict';
|
||||||
|
|
||||||
@@ -60,6 +63,7 @@ import { useDict } from '/@/hooks/dict';
|
|||||||
const FormDialog = defineAsyncComponent(() => import('./form.vue'));
|
const FormDialog = defineAsyncComponent(() => import('./form.vue'));
|
||||||
// 定义查询字典
|
// 定义查询字典
|
||||||
|
|
||||||
|
const { is_show } = useDict('is_show')
|
||||||
// 定义变量内容
|
// 定义变量内容
|
||||||
const formDialogRef = ref()
|
const formDialogRef = ref()
|
||||||
// 搜索变量
|
// 搜索变量
|
||||||
@@ -95,7 +99,7 @@ const resetQuery = () => {
|
|||||||
|
|
||||||
// 导出excel
|
// 导出excel
|
||||||
const exportExcel = () => {
|
const exportExcel = () => {
|
||||||
downBlobFile('/supermarket/mallProductSku/export', Object.assign(state.queryForm, { ids: selectObjs }), 'mallProductSku.xlsx')
|
downBlobFile('/integrated/meetingDeskLayout/export', Object.assign(state.queryForm, { ids: selectObjs }), 'meetingDeskLayout.xlsx')
|
||||||
}
|
}
|
||||||
|
|
||||||
// 多选事件
|
// 多选事件
|
||||||
@@ -34,8 +34,22 @@
|
|||||||
|
|
||||||
<el-col :span="12" class="mb20">
|
<el-col :span="12" class="mb20">
|
||||||
<el-form-item label="默认管理员" prop="adminId">
|
<el-form-item label="默认管理员" prop="adminId">
|
||||||
<el-select v-model="form.adminId" placeholder="请选择默认管理员">
|
<el-select
|
||||||
<el-option label="请选择">0</el-option>
|
v-model="form.adminId"
|
||||||
|
placeholder="请选择默认管理员"
|
||||||
|
clearable
|
||||||
|
filterable
|
||||||
|
remote
|
||||||
|
:remote-method="handleAdminUserSearch"
|
||||||
|
:loading="adminUserLoading"
|
||||||
|
@visible-change="handleAdminUserVisibleChange"
|
||||||
|
>
|
||||||
|
<el-option
|
||||||
|
v-for="item in adminUserOptions"
|
||||||
|
:key="item.id"
|
||||||
|
:label="item.nameWithMobile"
|
||||||
|
:value="item.id"
|
||||||
|
/>
|
||||||
</el-select>
|
</el-select>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
</el-col>
|
</el-col>
|
||||||
@@ -59,6 +73,19 @@
|
|||||||
</el-form-item>
|
</el-form-item>
|
||||||
</el-col>
|
</el-col>
|
||||||
|
|
||||||
|
<el-col :span="12" class="mb20">
|
||||||
|
<el-form-item label="会务人员" prop="serviceUserId">
|
||||||
|
<el-select v-model="form.serviceUserId" placeholder="请选择会务人员" clearable>
|
||||||
|
<el-option
|
||||||
|
v-for="item in serviceUserOptions"
|
||||||
|
:key="item.id"
|
||||||
|
:label="item.name || item.label || item.serviceUserName"
|
||||||
|
:value="item.id || item.value"
|
||||||
|
/>
|
||||||
|
</el-select>
|
||||||
|
</el-form-item>
|
||||||
|
</el-col>
|
||||||
|
|
||||||
<el-col :span="12" class="mb20">
|
<el-col :span="12" class="mb20">
|
||||||
<el-form-item label="可用时间段" prop="availableTime">
|
<el-form-item label="可用时间段" prop="availableTime">
|
||||||
<el-input v-model="form.availableTime" placeholder="请输入可用时间段"/>
|
<el-input v-model="form.availableTime" placeholder="请输入可用时间段"/>
|
||||||
@@ -159,6 +186,7 @@ import { useMessage } from "/src/hooks/message";
|
|||||||
import { getObj, addObj, putObj } from '/src/api/integrated/meetingRoom'
|
import { getObj, addObj, putObj } from '/src/api/integrated/meetingRoom'
|
||||||
import { fetchList } from '/src/api/integrated/meetingEquipment'
|
import { fetchList } from '/src/api/integrated/meetingEquipment'
|
||||||
import { dropdown } from '/src/api/integrated/cleanUser'
|
import { dropdown } from '/src/api/integrated/cleanUser'
|
||||||
|
import { getSimpleUserAll } from '/src/api/admin/user'
|
||||||
import { rule } from '/src/utils/validate';
|
import { rule } from '/src/utils/validate';
|
||||||
const emit = defineEmits(['refresh']);
|
const emit = defineEmits(['refresh']);
|
||||||
|
|
||||||
@@ -168,6 +196,10 @@ const visible = ref(false)
|
|||||||
const loading = ref(false)
|
const loading = ref(false)
|
||||||
const activeTab = ref('basic')
|
const activeTab = ref('basic')
|
||||||
const cleanUserOptions = ref<any[]>([])
|
const cleanUserOptions = ref<any[]>([])
|
||||||
|
const serviceUserOptions = ref<any[]>([])
|
||||||
|
const adminUserOptions = ref<any[]>([])
|
||||||
|
const adminUserLoading = ref(false)
|
||||||
|
const adminUserSearchKeyword = ref('')
|
||||||
|
|
||||||
interface Equipment {
|
interface Equipment {
|
||||||
equipId: string;
|
equipId: string;
|
||||||
@@ -213,6 +245,7 @@ const form = reactive({
|
|||||||
capacity: 0,
|
capacity: 0,
|
||||||
availableTime: '',
|
availableTime: '',
|
||||||
cleanUserId: '',
|
cleanUserId: '',
|
||||||
|
serviceUserId: '',
|
||||||
});
|
});
|
||||||
|
|
||||||
// 定义校验规则
|
// 定义校验规则
|
||||||
@@ -298,14 +331,18 @@ const openDialog = (id: string) => {
|
|||||||
form.id = ''
|
form.id = ''
|
||||||
equipmentList.value = []
|
equipmentList.value = []
|
||||||
form.cleanUserId = ''
|
form.cleanUserId = ''
|
||||||
|
form.serviceUserId = ''
|
||||||
|
|
||||||
// 重置表单数据
|
// 重置表单数据
|
||||||
nextTick(() => {
|
nextTick(() => {
|
||||||
dataFormRef.value?.resetFields();
|
dataFormRef.value?.resetFields();
|
||||||
});
|
});
|
||||||
|
|
||||||
// 获取保洁用户下拉数据
|
// 获取用户下拉数据(保洁和会务人员)
|
||||||
getCleanUserOptions()
|
getUserOptions()
|
||||||
|
|
||||||
|
// 获取管理员用户数据
|
||||||
|
getAdminUserOptions()
|
||||||
|
|
||||||
// 获取meetingRoom信息
|
// 获取meetingRoom信息
|
||||||
if (id) {
|
if (id) {
|
||||||
@@ -314,13 +351,61 @@ const openDialog = (id: string) => {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// 获取保洁用户下拉选项
|
// 获取用户下拉选项(保洁和会务人员)
|
||||||
const getCleanUserOptions = async () => {
|
const getUserOptions = async () => {
|
||||||
try {
|
try {
|
||||||
const res = await dropdown()
|
const res = await dropdown()
|
||||||
cleanUserOptions.value = Array.isArray(res.data) ? res.data : []
|
const allUsers = Array.isArray(res.data) ? res.data : []
|
||||||
|
|
||||||
|
// 根据type字段分别赋值(type为字符串类型)
|
||||||
|
cleanUserOptions.value = allUsers.filter(user => user.type === '1') // type: '1' 为保洁
|
||||||
|
serviceUserOptions.value = allUsers.filter(user => user.type === '2') // type: '2' 为会务人员
|
||||||
} catch (err: any) {
|
} catch (err: any) {
|
||||||
console.error('获取保洁用户列表失败:', err)
|
console.error('获取用户列表失败:', err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取管理员用户选项
|
||||||
|
const getAdminUserOptions = async (searchKeyword?: string) => {
|
||||||
|
try {
|
||||||
|
adminUserLoading.value = true
|
||||||
|
const params: any = {}
|
||||||
|
|
||||||
|
// 如果有搜索关键词,添加到参数中
|
||||||
|
if (searchKeyword) {
|
||||||
|
params.name = searchKeyword
|
||||||
|
params.mobile = searchKeyword
|
||||||
|
}
|
||||||
|
|
||||||
|
const res = await getSimpleUserAll(params)
|
||||||
|
let allUsers = Array.isArray(res.data) ? res.data : []
|
||||||
|
|
||||||
|
// 如果接口不支持搜索参数,在前端进行过滤
|
||||||
|
if (searchKeyword && allUsers.length > 0) {
|
||||||
|
allUsers = allUsers.filter(user =>
|
||||||
|
user.nameWithMobile.toLowerCase().includes(searchKeyword.toLowerCase())
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
adminUserOptions.value = allUsers
|
||||||
|
} catch (err: any) {
|
||||||
|
console.error('获取管理员用户列表失败:', err)
|
||||||
|
adminUserOptions.value = []
|
||||||
|
} finally {
|
||||||
|
adminUserLoading.value = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 管理员用户搜索处理
|
||||||
|
const handleAdminUserSearch = (keyword: string) => {
|
||||||
|
adminUserSearchKeyword.value = keyword
|
||||||
|
getAdminUserOptions(keyword)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 管理员用户下拉框显示状态变化
|
||||||
|
const handleAdminUserVisibleChange = (visible: boolean) => {
|
||||||
|
if (visible && adminUserOptions.value.length === 0) {
|
||||||
|
getAdminUserOptions()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -361,10 +446,13 @@ const getmeetingRoomData = (id: string) => {
|
|||||||
if (res.data.equipmentList) {
|
if (res.data.equipmentList) {
|
||||||
equipmentList.value = res.data.equipmentList
|
equipmentList.value = res.data.equipmentList
|
||||||
}
|
}
|
||||||
// 确保保洁信息正确回显
|
// 确保保洁和会务信息正确回显
|
||||||
if (res.data.cleanUserId) {
|
if (res.data.cleanUserId) {
|
||||||
form.cleanUserId = res.data.cleanUserId
|
form.cleanUserId = res.data.cleanUserId
|
||||||
}
|
}
|
||||||
|
if (res.data.serviceUserId) {
|
||||||
|
form.serviceUserId = res.data.serviceUserId
|
||||||
|
}
|
||||||
}).finally(() => {
|
}).finally(() => {
|
||||||
loading.value = false
|
loading.value = false
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -35,6 +35,8 @@
|
|||||||
<el-table-column prop="location" label="位置" show-overflow-tooltip/>
|
<el-table-column prop="location" label="位置" show-overflow-tooltip/>
|
||||||
<el-table-column prop="capacity" label="容纳人数" show-overflow-tooltip/>
|
<el-table-column prop="capacity" label="容纳人数" show-overflow-tooltip/>
|
||||||
<el-table-column prop="availableTime" label="可用时间段" show-overflow-tooltip/>
|
<el-table-column prop="availableTime" label="可用时间段" show-overflow-tooltip/>
|
||||||
|
<el-table-column prop="cleanUserId" label="保洁人员" show-overflow-tooltip/>
|
||||||
|
<el-table-column prop="serviceUserId" label="会务人员" show-overflow-tooltip/>
|
||||||
<el-table-column label="操作" width="150">
|
<el-table-column label="操作" width="150">
|
||||||
<template #default="scope">
|
<template #default="scope">
|
||||||
<el-button icon="edit-pen" text type="primary" v-auth="'integrated_meetingRoom_edit'"
|
<el-button icon="edit-pen" text type="primary" v-auth="'integrated_meetingRoom_edit'"
|
||||||
|
|||||||
@@ -0,0 +1,116 @@
|
|||||||
|
<template>
|
||||||
|
<el-dialog :title="form.id ? '编辑' : '新增'" v-model="visible"
|
||||||
|
:close-on-click-modal="false" draggable>
|
||||||
|
<el-form ref="dataFormRef" :model="form" :rules="dataRules" label-width="90px" v-loading="loading">
|
||||||
|
<el-row :gutter="24">
|
||||||
|
<el-col :span="12" class="mb20">
|
||||||
|
<el-form-item label="姓名" prop="name">
|
||||||
|
<el-input v-model="form.name" placeholder="请输入姓名"/>
|
||||||
|
</el-form-item>
|
||||||
|
</el-col>
|
||||||
|
|
||||||
|
<el-col :span="12" class="mb20">
|
||||||
|
<el-form-item label="手机号" prop="phone">
|
||||||
|
<el-input v-model="form.phone" placeholder="请输入手机号"/>
|
||||||
|
</el-form-item>
|
||||||
|
</el-col>
|
||||||
|
|
||||||
|
|
||||||
|
<el-col :span="12" class="mb20">
|
||||||
|
<el-form-item label="照片" prop="picUrl">
|
||||||
|
<upload-img v-model="form.picUrl"></upload-img>
|
||||||
|
</el-form-item>
|
||||||
|
</el-col>
|
||||||
|
|
||||||
|
</el-row>
|
||||||
|
</el-form>
|
||||||
|
<template #footer>
|
||||||
|
<span class="dialog-footer">
|
||||||
|
<el-button @click="visible = false">取消</el-button>
|
||||||
|
<el-button type="primary" @click="onSubmit" :disabled="loading">确认</el-button>
|
||||||
|
</span>
|
||||||
|
</template>
|
||||||
|
</el-dialog>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts" name="ServiceUserDialog">
|
||||||
|
import { ref, reactive, nextTick } from 'vue';
|
||||||
|
import { useDict } from '/src/hooks/dict';
|
||||||
|
import { useMessage } from "/src/hooks/message";
|
||||||
|
import { getObj, addObj, putObj } from '/src/api/integrated/cleanUser'
|
||||||
|
import { rule } from '/src/utils/validate';
|
||||||
|
const emit = defineEmits(['refresh']);
|
||||||
|
|
||||||
|
// 定义变量内容
|
||||||
|
const dataFormRef = ref();
|
||||||
|
const visible = ref(false)
|
||||||
|
const loading = ref(false)
|
||||||
|
// 定义字典
|
||||||
|
|
||||||
|
// 提交表单数据
|
||||||
|
const form = reactive({
|
||||||
|
id:'',
|
||||||
|
name: '',
|
||||||
|
phone: '',
|
||||||
|
picUrl: '',
|
||||||
|
type: '2', // 会务人员
|
||||||
|
});
|
||||||
|
|
||||||
|
// 定义校验规则
|
||||||
|
const dataRules = ref({
|
||||||
|
name: [{required: true, message: '姓名不能为空', trigger: 'blur'}],
|
||||||
|
phone: [{required: true, message: '手机号不能为空', trigger: 'blur'}],
|
||||||
|
})
|
||||||
|
|
||||||
|
// 打开弹窗
|
||||||
|
const openDialog = (id: string) => {
|
||||||
|
visible.value = true
|
||||||
|
form.id = ''
|
||||||
|
|
||||||
|
// 重置表单数据
|
||||||
|
nextTick(() => {
|
||||||
|
dataFormRef.value?.resetFields();
|
||||||
|
});
|
||||||
|
|
||||||
|
// 获取serviceUser信息
|
||||||
|
if (id) {
|
||||||
|
form.id = id
|
||||||
|
getserviceUserData(id)
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// 提交
|
||||||
|
const onSubmit = async () => {
|
||||||
|
const valid = await dataFormRef.value.validate().catch(() => {});
|
||||||
|
if (!valid) return false;
|
||||||
|
|
||||||
|
try {
|
||||||
|
loading.value = true;
|
||||||
|
form.id ? await putObj(form) : await addObj(form);
|
||||||
|
useMessage().success(form.id ? '修改成功' : '添加成功');
|
||||||
|
visible.value = false;
|
||||||
|
emit('refresh');
|
||||||
|
} catch (err: any) {
|
||||||
|
useMessage().error(err.msg);
|
||||||
|
} finally {
|
||||||
|
loading.value = false;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
// 初始化表单数据
|
||||||
|
const getserviceUserData = (id: string) => {
|
||||||
|
// 获取数据
|
||||||
|
loading.value = true
|
||||||
|
getObj(id).then((res: any) => {
|
||||||
|
Object.assign(form, res.data)
|
||||||
|
}).finally(() => {
|
||||||
|
loading.value = false
|
||||||
|
})
|
||||||
|
};
|
||||||
|
|
||||||
|
// 暴露变量
|
||||||
|
defineExpose({
|
||||||
|
openDialog
|
||||||
|
});
|
||||||
|
</script>
|
||||||
@@ -0,0 +1,132 @@
|
|||||||
|
<template>
|
||||||
|
<div class="layout-padding">
|
||||||
|
<div class="layout-padding-auto layout-padding-view">
|
||||||
|
<el-row v-show="showSearch">
|
||||||
|
<el-form :model="state.queryForm" ref="queryRef" :inline="true" @keyup.enter="getDataList">
|
||||||
|
<el-form-item label="姓名" prop="name" >
|
||||||
|
<el-input placeholder="请输入姓名" v-model="state.queryForm.name" />
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="手机号" prop="phone" >
|
||||||
|
<el-input placeholder="请输入手机号" v-model="state.queryForm.phone" />
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item>
|
||||||
|
<el-button icon="search" type="primary" @click="getDataList">
|
||||||
|
查询
|
||||||
|
</el-button>
|
||||||
|
<el-button icon="Refresh" @click="resetQuery">重置</el-button>
|
||||||
|
</el-form-item>
|
||||||
|
</el-form>
|
||||||
|
</el-row>
|
||||||
|
<el-row>
|
||||||
|
<div class="mb8" style="width: 100%">
|
||||||
|
<el-button icon="folder-add" type="primary" class="ml10" @click="formDialogRef.openDialog()"
|
||||||
|
v-auth="'integrated_cleanUser_add'">
|
||||||
|
新 增
|
||||||
|
</el-button>
|
||||||
|
<el-button plain :disabled="multiple" icon="Delete" type="primary"
|
||||||
|
v-auth="'integrated_cleanUser_del'" @click="handleDelete(selectObjs)">
|
||||||
|
删除
|
||||||
|
</el-button>
|
||||||
|
<right-toolbar v-model:showSearch="showSearch" :export="'integrated_cleanUser_export'"
|
||||||
|
@exportExcel="exportExcel" class="ml10 mr20" style="float: right;"
|
||||||
|
@queryTable="getDataList"></right-toolbar>
|
||||||
|
</div>
|
||||||
|
</el-row>
|
||||||
|
<el-table :data="state.dataList" v-loading="state.loading" border
|
||||||
|
:cell-style="tableStyle.cellStyle" :header-cell-style="tableStyle.headerCellStyle"
|
||||||
|
@selection-change="selectionChangHandle"
|
||||||
|
@sort-change="sortChangeHandle">
|
||||||
|
<el-table-column type="selection" width="40" align="center" />
|
||||||
|
<el-table-column type="index" label="#" width="40" />
|
||||||
|
<el-table-column prop="name" label="姓名" show-overflow-tooltip/>
|
||||||
|
<el-table-column prop="phone" label="手机号" show-overflow-tooltip/>
|
||||||
|
<el-table-column prop="picUrl" label="照片" show-overflow-tooltip/>
|
||||||
|
<el-table-column label="操作" width="150">
|
||||||
|
<template #default="scope">
|
||||||
|
<el-button icon="edit-pen" text type="primary" v-auth="'integrated_cleanUser_edit'"
|
||||||
|
@click="formDialogRef.openDialog(scope.row.id)">编辑</el-button>
|
||||||
|
<el-button icon="delete" text type="primary" v-auth="'integrated_cleanUser_del'" @click="handleDelete([scope.row.id])">删除</el-button>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
</el-table>
|
||||||
|
<pagination @size-change="sizeChangeHandle" @current-change="currentChangeHandle" v-bind="state.pagination" />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 编辑、新增 -->
|
||||||
|
<form-dialog ref="formDialogRef" @refresh="getDataList(false)" />
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts" name="systemServiceUser">
|
||||||
|
import { ref, reactive, defineAsyncComponent } from 'vue';
|
||||||
|
import { BasicTableProps, useTable } from "/src/hooks/table";
|
||||||
|
import { fetchList, delObjs } from "/src/api/integrated/cleanUser";
|
||||||
|
import { useMessage, useMessageBox } from "/src/hooks/message";
|
||||||
|
import { useDict } from '/src/hooks/dict';
|
||||||
|
|
||||||
|
// 引入组件
|
||||||
|
const FormDialog = defineAsyncComponent(() => import('./form.vue'));
|
||||||
|
// 定义查询字典
|
||||||
|
|
||||||
|
// 定义变量内容
|
||||||
|
const formDialogRef = ref()
|
||||||
|
// 搜索变量
|
||||||
|
const queryRef = ref()
|
||||||
|
const showSearch = ref(true)
|
||||||
|
// 多选变量
|
||||||
|
const selectObjs = ref([]) as any
|
||||||
|
const multiple = ref(true)
|
||||||
|
|
||||||
|
const state: BasicTableProps = reactive<BasicTableProps>({
|
||||||
|
queryForm: { type: '2' }, // 会务人员
|
||||||
|
pageList: (params: any) => fetchList({ ...params, type: '2' })
|
||||||
|
})
|
||||||
|
|
||||||
|
// table hook
|
||||||
|
const {
|
||||||
|
getDataList,
|
||||||
|
currentChangeHandle,
|
||||||
|
sizeChangeHandle,
|
||||||
|
sortChangeHandle,
|
||||||
|
downBlobFile,
|
||||||
|
tableStyle
|
||||||
|
} = useTable(state)
|
||||||
|
|
||||||
|
// 清空搜索条件
|
||||||
|
const resetQuery = () => {
|
||||||
|
// 清空搜索条件
|
||||||
|
queryRef.value?.resetFields()
|
||||||
|
// 清空多选
|
||||||
|
selectObjs.value = []
|
||||||
|
getDataList()
|
||||||
|
}
|
||||||
|
|
||||||
|
// 导出excel
|
||||||
|
const exportExcel = () => {
|
||||||
|
downBlobFile('/integrated/cleanUser/export', Object.assign(state.queryForm, { ids: selectObjs }), 'serviceUser.xlsx')
|
||||||
|
}
|
||||||
|
|
||||||
|
// 多选事件
|
||||||
|
const selectionChangHandle = (objs: { id: string }[]) => {
|
||||||
|
selectObjs.value = objs.map(({ id }) => id);
|
||||||
|
multiple.value = !objs.length;
|
||||||
|
};
|
||||||
|
|
||||||
|
// 删除操作
|
||||||
|
const handleDelete = async (ids: string[]) => {
|
||||||
|
try {
|
||||||
|
await useMessageBox().confirm('此操作将永久删除');
|
||||||
|
} catch {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
await delObjs(ids);
|
||||||
|
getDataList();
|
||||||
|
useMessage().success('删除成功');
|
||||||
|
} catch (err: any) {
|
||||||
|
useMessage().error(err.msg);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
</script>
|
||||||
@@ -1,160 +1,177 @@
|
|||||||
<template>
|
<template>
|
||||||
<el-dialog :title="form.id ? '编辑' : '新增'" v-model="visible"
|
<el-dialog :title="form.id ? '编辑' : '新增'" v-model="visible" :close-on-click-modal="false" draggable>
|
||||||
:close-on-click-modal="false" draggable>
|
<el-form ref="dataFormRef" :model="form" :rules="dataRules" formDialogRef label-width="90px" v-loading="loading">
|
||||||
<el-form ref="dataFormRef" :model="form" :rules="dataRules" formDialogRef label-width="90px" v-loading="loading">
|
<el-row :gutter="24">
|
||||||
<el-row :gutter="24">
|
<el-col :span="12" class="mb20">
|
||||||
<el-col :span="12" class="mb20">
|
<el-form-item label="商户" prop="merchantId" required>
|
||||||
<el-form-item label="父级分类" prop="parentId">
|
<el-select v-model="form.merchantId" placeholder="请选择商户" clearable>
|
||||||
<el-select v-model="form.parentId" clearable placeholder="请选择父级分类">
|
<el-option v-for="merchant in merchantOptions" :key="merchant.value" :label="merchant.label" :value="merchant.value" />
|
||||||
<el-option
|
</el-select>
|
||||||
v-for="item in categoryOptions"
|
</el-form-item>
|
||||||
:key="item.id"
|
</el-col>
|
||||||
:label="item.name"
|
|
||||||
:value="item.id"
|
|
||||||
/>
|
|
||||||
</el-select>
|
|
||||||
</el-form-item>
|
|
||||||
</el-col>
|
|
||||||
|
|
||||||
<el-col :span="12" class="mb20">
|
<el-col :span="12" class="mb20">
|
||||||
<el-form-item label="分类名称" prop="name">
|
<el-form-item label="父级分类" prop="parentId">
|
||||||
<el-input v-model="form.name" placeholder="请输入分类名称"/>
|
<el-select v-model="form.parentId" clearable placeholder="请选择父级分类">
|
||||||
</el-form-item>
|
<el-option v-for="item in categoryOptions" :key="item.id" :label="item.name" :value="item.id" />
|
||||||
</el-col>
|
</el-select>
|
||||||
|
</el-form-item>
|
||||||
|
</el-col>
|
||||||
|
|
||||||
<el-col :span="12" class="mb20">
|
<el-col :span="12" class="mb20">
|
||||||
<el-form-item label="排序" prop="sort">
|
<el-form-item label="分类名称" prop="name">
|
||||||
<el-input-number :min="1" :max="1000" v-model="form.sort" placeholder="请输入排序"></el-input-number>
|
<el-input v-model="form.name" placeholder="请输入分类名称" />
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
</el-col>
|
</el-col>
|
||||||
|
|
||||||
<el-col :span="12" class="mb20">
|
<el-col :span="12" class="mb20">
|
||||||
<el-form-item label="状态(0正常,1下架)" prop="status">
|
<el-form-item label="排序" prop="sort">
|
||||||
<el-radio-group v-model="form.status">
|
<el-input-number :min="1" :max="1000" v-model="form.sort" placeholder="请输入排序"></el-input-number>
|
||||||
<el-radio :label="item.value" v-for="(item, index) in status" border :key="index">{{ item.label }}
|
</el-form-item>
|
||||||
</el-radio>
|
</el-col>
|
||||||
</el-radio-group>
|
|
||||||
</el-form-item>
|
|
||||||
</el-col>
|
|
||||||
|
|
||||||
<el-col :span="12" class="mb20">
|
<el-col :span="12" class="mb20">
|
||||||
<el-form-item label="分类图片" prop="picUrl">
|
<el-form-item label="状态" prop="status">
|
||||||
<upload-img v-model="form.picUrl"></upload-img>
|
<el-radio-group v-model="form.status">
|
||||||
</el-form-item>
|
<el-radio :label="item.value" v-for="(item, index) in status" border :key="index">{{ item.label }} </el-radio>
|
||||||
</el-col>
|
</el-radio-group>
|
||||||
|
</el-form-item>
|
||||||
|
</el-col>
|
||||||
|
|
||||||
|
<el-col :span="12" class="mb20">
|
||||||
|
<el-form-item label="分类图片" prop="picUrl">
|
||||||
|
<upload-img v-model:imageUrl="form.picUrl"></upload-img>
|
||||||
|
</el-form-item>
|
||||||
|
</el-col>
|
||||||
</el-row>
|
</el-row>
|
||||||
</el-form>
|
</el-form>
|
||||||
<template #footer>
|
<template #footer>
|
||||||
<span class="dialog-footer">
|
<span class="dialog-footer">
|
||||||
<el-button @click="visible = false">取消</el-button>
|
<el-button @click="visible = false">取消</el-button>
|
||||||
<el-button type="primary" @click="onSubmit" :disabled="loading">确认</el-button>
|
<el-button type="primary" @click="onSubmit" :disabled="loading">确认</el-button>
|
||||||
</span>
|
</span>
|
||||||
</template>
|
</template>
|
||||||
</el-dialog>
|
</el-dialog>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts" name="mallCategoryDialog">
|
<script setup lang="ts" name="mallCategoryDialog">
|
||||||
import { useDict } from '/@/hooks/dict';
|
import { useDict } from "/@/hooks/dict"
|
||||||
import { useMessage } from "/@/hooks/message";
|
import { useMessage } from "/@/hooks/message"
|
||||||
import { getObj, addObj, putObj, fetchList } from '/@/api/supermarket/mallCategory'
|
import { getObj, addObj, putObj, fetchList } from "/@/api/supermarket/mallCategory"
|
||||||
import { rule } from '/@/utils/validate';
|
import { selectOption as fetchMerchantSelect } from "/@/api/supermarket/mallMerchant"
|
||||||
import { ref, reactive, nextTick, onMounted } from 'vue';
|
import { rule } from "/@/utils/validate"
|
||||||
const emit = defineEmits(['refresh']);
|
import { ref, reactive, nextTick, onMounted } from "vue"
|
||||||
|
const emit = defineEmits(["refresh"])
|
||||||
|
|
||||||
// 定义变量内容
|
// 定义变量内容
|
||||||
const dataFormRef = ref();
|
const dataFormRef = ref()
|
||||||
const visible = ref(false)
|
const visible = ref(false)
|
||||||
const loading = ref(false)
|
const loading = ref(false)
|
||||||
// 定义字典
|
// 定义字典
|
||||||
const { status } = useDict('status')
|
const { status } = useDict("status")
|
||||||
|
|
||||||
// 提交表单数据
|
// 提交表单数据
|
||||||
const form = reactive({
|
const form = reactive({
|
||||||
id:'',
|
id: "",
|
||||||
parentId: '',
|
merchantId: "",
|
||||||
name: '',
|
parentId: "",
|
||||||
sort: 0,
|
name: "",
|
||||||
status: '0',
|
sort: 0,
|
||||||
picUrl: '',
|
status: "0",
|
||||||
});
|
picUrl: "",
|
||||||
|
})
|
||||||
|
|
||||||
// 定义校验规则
|
// 定义校验规则
|
||||||
const dataRules = ref({
|
const dataRules = ref({
|
||||||
name: [{required: true, message: '分类名称不能为空', trigger: 'blur'}],
|
merchantId: [{ required: true, message: "商户不能为空", trigger: "change" }],
|
||||||
|
name: [{ required: true, message: "分类名称不能为空", trigger: "blur" }],
|
||||||
})
|
})
|
||||||
|
|
||||||
// 分类选项
|
// 分类选项
|
||||||
const categoryOptions = ref<any[]>([]);
|
const categoryOptions = ref<any[]>([])
|
||||||
|
|
||||||
|
// 商户选项
|
||||||
|
const merchantOptions = ref<any[]>([])
|
||||||
|
|
||||||
// 获取所有分类(排除自身)
|
// 获取所有分类(排除自身)
|
||||||
const loadCategories = async () => {
|
const loadCategories = async () => {
|
||||||
const res = await fetchList({ size: 9999 });
|
const res = await fetchList({ size: 9999 })
|
||||||
if (res && res.data && res.data.records) {
|
if (res && res.data && res.data.records) {
|
||||||
// 排除自己,避免自己作为自己的父级
|
// 排除自己,避免自己作为自己的父级
|
||||||
categoryOptions.value = res.data.records.filter((item: any) => item.id !== form.id);
|
categoryOptions.value = res.data.records.filter((item: any) => item.id !== form.id)
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
|
|
||||||
|
// 加载商户选项
|
||||||
|
const loadMerchantOptions = async () => {
|
||||||
|
const res = await fetchMerchantSelect()
|
||||||
|
merchantOptions.value = res.data || []
|
||||||
|
}
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
loadCategories();
|
loadCategories()
|
||||||
});
|
loadMerchantOptions()
|
||||||
|
})
|
||||||
|
|
||||||
// 打开弹窗
|
// 打开弹窗
|
||||||
const openDialog = (id: string) => {
|
const openDialog = (id: string) => {
|
||||||
visible.value = true
|
visible.value = true
|
||||||
form.id = ''
|
form.id = ""
|
||||||
|
|
||||||
// 重置表单数据
|
// 重置表单数据
|
||||||
nextTick(() => {
|
nextTick(() => {
|
||||||
dataFormRef.value?.resetFields();
|
dataFormRef.value?.resetFields()
|
||||||
form.status = '0';
|
form.merchantId = ""
|
||||||
});
|
form.status = "0"
|
||||||
|
})
|
||||||
|
|
||||||
// 获取mallCategory信息
|
// 获取mallCategory信息
|
||||||
if (id) {
|
if (id) {
|
||||||
form.id = id
|
form.id = id
|
||||||
getmallCategoryData(id)
|
getmallCategoryData(id)
|
||||||
} else {
|
} else {
|
||||||
// 新增时直接加载分类
|
// 新增时直接加载分类和商户
|
||||||
loadCategories();
|
loadCategories()
|
||||||
}
|
loadMerchantOptions()
|
||||||
};
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// 提交
|
// 提交
|
||||||
const onSubmit = async () => {
|
const onSubmit = async () => {
|
||||||
const valid = await dataFormRef.value.validate().catch(() => {});
|
const valid = await dataFormRef.value.validate().catch(() => {})
|
||||||
if (!valid) return false;
|
if (!valid) return false
|
||||||
|
|
||||||
try {
|
try {
|
||||||
loading.value = true;
|
loading.value = true
|
||||||
form.id ? await putObj(form) : await addObj(form);
|
form.id ? await putObj(form) : await addObj(form)
|
||||||
useMessage().success(form.id ? '修改成功' : '添加成功');
|
useMessage().success(form.id ? "修改成功" : "添加成功")
|
||||||
visible.value = false;
|
visible.value = false
|
||||||
emit('refresh');
|
emit("refresh")
|
||||||
} catch (err: any) {
|
} catch (err: any) {
|
||||||
useMessage().error(err.msg);
|
useMessage().error(err.msg)
|
||||||
} finally {
|
} finally {
|
||||||
loading.value = false;
|
loading.value = false
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
|
|
||||||
|
|
||||||
// 初始化表单数据
|
// 初始化表单数据
|
||||||
const getmallCategoryData = (id: string) => {
|
const getmallCategoryData = (id: string) => {
|
||||||
// 获取数据
|
// 获取数据
|
||||||
loading.value = true
|
loading.value = true
|
||||||
getObj(id).then((res: any) => {
|
getObj(id)
|
||||||
Object.assign(form, res.data)
|
.then((res: any) => {
|
||||||
// 编辑时加载分类并排除自己
|
Object.assign(form, res.data)
|
||||||
loadCategories();
|
// 编辑时加载分类和商户并排除自己
|
||||||
}).finally(() => {
|
loadCategories()
|
||||||
loading.value = false
|
loadMerchantOptions()
|
||||||
})
|
})
|
||||||
};
|
.finally(() => {
|
||||||
|
loading.value = false
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
// 暴露变量
|
// 暴露变量
|
||||||
defineExpose({
|
defineExpose({
|
||||||
openDialog
|
openDialog,
|
||||||
});
|
})
|
||||||
</script>
|
</script>
|
||||||
@@ -1,84 +1,109 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="layout-padding">
|
<div class="layout-padding">
|
||||||
<div class="layout-padding-auto layout-padding-view">
|
<div class="layout-padding-auto layout-padding-view">
|
||||||
<el-row v-show="showSearch">
|
<el-row v-show="showSearch">
|
||||||
<el-form :model="state.queryForm" ref="queryRef" :inline="true" @keyup.enter="getDataList">
|
<el-form :model="state.queryForm" ref="queryRef" :inline="true" @keyup.enter="getDataList">
|
||||||
<el-form-item label="分类名称" prop="name" >
|
<el-form-item label="分类名称" prop="name">
|
||||||
<el-input placeholder="请输入分类名称" v-model="state.queryForm.name" />
|
<el-input placeholder="请输入分类名称" v-model="state.queryForm.name" />
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item>
|
<el-form-item>
|
||||||
<el-button icon="search" type="primary" @click="getDataList">
|
<el-button icon="search" type="primary" @click="getDataList"> 查询 </el-button>
|
||||||
查询
|
<el-button icon="Refresh" @click="resetQuery">重置</el-button>
|
||||||
</el-button>
|
</el-form-item>
|
||||||
<el-button icon="Refresh" @click="resetQuery">重置</el-button>
|
</el-form>
|
||||||
</el-form-item>
|
</el-row>
|
||||||
</el-form>
|
<el-row>
|
||||||
</el-row>
|
<div class="mb8" style="width: 100%">
|
||||||
<el-row>
|
<el-button
|
||||||
<div class="mb8" style="width: 100%">
|
icon="folder-add"
|
||||||
<el-button icon="folder-add" type="primary" class="ml10" @click="formDialogRef.openDialog()"
|
type="primary"
|
||||||
v-auth="'supermarket_mallCategory_add'">
|
class="ml10"
|
||||||
新 增
|
@click="formDialogRef.openDialog()"
|
||||||
</el-button>
|
v-auth="'supermarket_mallCategory_add'"
|
||||||
<el-button plain :disabled="multiple" icon="Delete" type="primary"
|
>
|
||||||
v-auth="'supermarket_mallCategory_del'" @click="handleDelete(selectObjs)">
|
新 增
|
||||||
删除
|
</el-button>
|
||||||
</el-button>
|
<el-button
|
||||||
<right-toolbar v-model:showSearch="showSearch" :export="'supermarket_mallCategory_export'"
|
plain
|
||||||
@exportExcel="exportExcel" class="ml10 mr20" style="float: right;"
|
:disabled="multiple"
|
||||||
@queryTable="getDataList"></right-toolbar>
|
icon="Delete"
|
||||||
</div>
|
type="primary"
|
||||||
</el-row>
|
v-auth="'supermarket_mallCategory_del'"
|
||||||
<el-table
|
@click="handleDelete(selectObjs)"
|
||||||
:data="treeData"
|
>
|
||||||
row-key="id"
|
删除
|
||||||
:tree-props="{ children: 'children' }"
|
</el-button>
|
||||||
v-loading="state.loading"
|
<right-toolbar
|
||||||
border
|
v-model:showSearch="showSearch"
|
||||||
:cell-style="tableStyle.cellStyle"
|
:export="'supermarket_mallCategory_export'"
|
||||||
:header-cell-style="tableStyle.headerCellStyle"
|
@exportExcel="exportExcel"
|
||||||
@selection-change="selectionChangHandle"
|
class="ml10 mr20"
|
||||||
@sort-change="sortChangeHandle"
|
style="float: right"
|
||||||
>
|
@queryTable="getDataList"
|
||||||
<el-table-column type="selection" width="40" align="center" />
|
></right-toolbar>
|
||||||
<el-table-column type="index" label="#" width="40" />
|
</div>
|
||||||
<el-table-column prop="name" label="分类名称" show-overflow-tooltip/>
|
</el-row>
|
||||||
<el-table-column prop="sort" label="排序" show-overflow-tooltip/>
|
<el-table
|
||||||
<el-table-column prop="status" label="状态(0正常,1下架)" show-overflow-tooltip>
|
:data="treeData"
|
||||||
<template #default="scope">
|
row-key="id"
|
||||||
<dict-tag :options="status" :value="scope.row.status"></dict-tag>
|
:tree-props="{ children: 'children' }"
|
||||||
</template>
|
v-loading="state.loading"
|
||||||
</el-table-column>
|
border
|
||||||
<el-table-column prop="picUrl" label="分类图片" show-overflow-tooltip/>
|
:cell-style="tableStyle.cellStyle"
|
||||||
<el-table-column label="操作" width="150">
|
:header-cell-style="tableStyle.headerCellStyle"
|
||||||
<template #default="scope">
|
@selection-change="selectionChangHandle"
|
||||||
<el-button icon="edit-pen" text type="primary" v-auth="'supermarket_mallCategory_edit'"
|
@sort-change="sortChangeHandle"
|
||||||
@click="formDialogRef.openDialog(scope.row.id)">编辑</el-button>
|
>
|
||||||
<el-button icon="delete" text type="primary" v-auth="'supermarket_mallCategory_del'" @click="handleDelete([scope.row.id])">删除</el-button>
|
<el-table-column type="selection" width="50" align="center" />
|
||||||
</template>
|
<el-table-column type="index" label="#" width="40" />
|
||||||
</el-table-column>
|
<el-table-column prop="name" label="分类名称" show-overflow-tooltip />
|
||||||
</el-table>
|
<el-table-column prop="sort" label="排序" show-overflow-tooltip />
|
||||||
<!-- <pagination @size-change="sizeChangeHandle" @current-change="currentChangeHandle" v-bind="state.pagination" /> -->
|
<el-table-column prop="status" label="状态" show-overflow-tooltip>
|
||||||
</div>
|
<template #default="scope">
|
||||||
|
<dict-tag :options="status" :value="scope.row.status"></dict-tag>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
<el-table-column prop="picUrl" label="分类图片" show-overflow-tooltip>
|
||||||
|
<template #default="scope">
|
||||||
|
<preview-image :src="scope.row.picUrl" />
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
<el-table-column label="操作" width="150">
|
||||||
|
<template #default="scope">
|
||||||
|
<el-button
|
||||||
|
icon="edit-pen"
|
||||||
|
text
|
||||||
|
type="primary"
|
||||||
|
v-auth="'supermarket_mallCategory_edit'"
|
||||||
|
@click="formDialogRef.openDialog(scope.row.id)"
|
||||||
|
>编辑</el-button
|
||||||
|
>
|
||||||
|
<el-button icon="delete" text type="primary" v-auth="'supermarket_mallCategory_del'" @click="handleDelete([scope.row.id])"
|
||||||
|
>删除</el-button
|
||||||
|
>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
</el-table>
|
||||||
|
<!-- <pagination @size-change="sizeChangeHandle" @current-change="currentChangeHandle" v-bind="state.pagination" /> -->
|
||||||
|
</div>
|
||||||
|
|
||||||
<!-- 编辑、新增 -->
|
<!-- 编辑、新增 -->
|
||||||
<form-dialog ref="formDialogRef" @refresh="getDataList()" />
|
<form-dialog ref="formDialogRef" @refresh="getDataList()" />
|
||||||
|
</div>
|
||||||
</div>
|
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts" name="systemMallCategory">
|
<script setup lang="ts" name="systemMallCategory">
|
||||||
import { BasicTableProps, useTable } from "/@/hooks/table";
|
import { BasicTableProps, useTable } from "/@/hooks/table"
|
||||||
import { fetchList, delObjs, tree as fetchTree, putObj } from "/@/api/supermarket/mallCategory";
|
import { fetchList, delObjs, tree as fetchTree, putObj } from "/@/api/supermarket/mallCategory"
|
||||||
import { useMessage, useMessageBox } from "/@/hooks/message";
|
import { useMessage, useMessageBox } from "/@/hooks/message"
|
||||||
import { useDict } from '/@/hooks/dict';
|
import { useDict } from "/@/hooks/dict"
|
||||||
import { ref, reactive, onMounted, defineExpose } from 'vue';
|
import { ref, reactive, onMounted, defineExpose } from "vue"
|
||||||
|
|
||||||
// 引入组件
|
// 引入组件
|
||||||
const FormDialog = defineAsyncComponent(() => import('./form.vue'));
|
const FormDialog = defineAsyncComponent(() => import("./form.vue"))
|
||||||
// 定义查询字典
|
// 定义查询字典
|
||||||
|
|
||||||
const { status } = useDict('status')
|
const { status } = useDict("status")
|
||||||
// 定义变量内容
|
// 定义变量内容
|
||||||
const formDialogRef = ref()
|
const formDialogRef = ref()
|
||||||
// 搜索变量
|
// 搜索变量
|
||||||
@@ -89,91 +114,85 @@ const selectObjs = ref([]) as any
|
|||||||
const multiple = ref(true)
|
const multiple = ref(true)
|
||||||
|
|
||||||
const state: BasicTableProps = reactive<BasicTableProps>({
|
const state: BasicTableProps = reactive<BasicTableProps>({
|
||||||
queryForm: {},
|
queryForm: {},
|
||||||
pageList: fetchList,
|
pageList: fetchList,
|
||||||
loading: false,
|
loading: false,
|
||||||
pagination: { total: 0 }
|
pagination: { total: 0 },
|
||||||
})
|
})
|
||||||
|
|
||||||
const treeData = ref<any[]>([])
|
const treeData = ref<any[]>([])
|
||||||
|
|
||||||
function listToTree(list: any[]): any[] {
|
function listToTree(list: any[]): any[] {
|
||||||
const map = new Map<string, any>();
|
const map = new Map<string, any>()
|
||||||
list.forEach((item: any) => {
|
list.forEach((item: any) => {
|
||||||
item.children = [];
|
item.children = []
|
||||||
map.set(item.id, item);
|
map.set(item.id, item)
|
||||||
});
|
})
|
||||||
const tree: any[] = [];
|
const tree: any[] = []
|
||||||
list.forEach((item: any) => {
|
list.forEach((item: any) => {
|
||||||
if (item.parentId && item.parentId !== '0' && map.has(item.parentId)) {
|
if (item.parentId && item.parentId !== "0" && map.has(item.parentId)) {
|
||||||
map.get(item.parentId).children.push(item);
|
map.get(item.parentId).children.push(item)
|
||||||
} else {
|
} else {
|
||||||
tree.push(item);
|
tree.push(item)
|
||||||
}
|
}
|
||||||
});
|
})
|
||||||
return tree;
|
return tree
|
||||||
}
|
}
|
||||||
|
|
||||||
const getDataList = async () => {
|
const getDataList = async () => {
|
||||||
state.loading = true;
|
state.loading = true
|
||||||
try {
|
try {
|
||||||
const res = await fetchTree();
|
const res = await fetchTree()
|
||||||
treeData.value = res.data || [];
|
treeData.value = res.data || []
|
||||||
(state.pagination as any).total = Array.isArray(res.data) ? res.data.length : 0;
|
;(state.pagination as any).total = Array.isArray(res.data) ? res.data.length : 0
|
||||||
} finally {
|
} finally {
|
||||||
state.loading = false;
|
state.loading = false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
getDataList();
|
getDataList()
|
||||||
})
|
})
|
||||||
|
|
||||||
// table hook
|
// table hook
|
||||||
const {
|
const { currentChangeHandle, sizeChangeHandle, sortChangeHandle, downBlobFile, tableStyle } = useTable(state)
|
||||||
currentChangeHandle,
|
|
||||||
sizeChangeHandle,
|
|
||||||
sortChangeHandle,
|
|
||||||
downBlobFile,
|
|
||||||
tableStyle
|
|
||||||
} = useTable(state)
|
|
||||||
|
|
||||||
// 清空搜索条件
|
// 清空搜索条件
|
||||||
const resetQuery = () => {
|
const resetQuery = () => {
|
||||||
queryRef.value?.resetFields()
|
queryRef.value?.resetFields()
|
||||||
selectObjs.value = []
|
selectObjs.value = []
|
||||||
getDataList()
|
getDataList()
|
||||||
}
|
}
|
||||||
|
|
||||||
// 导出excel
|
// 导出excel
|
||||||
const exportExcel = () => {
|
const exportExcel = () => {
|
||||||
downBlobFile('/supermarket/mallCategory/export', Object.assign(state.queryForm, { ids: selectObjs }), 'mallCategory.xlsx')
|
downBlobFile("/supermarket/mallCategory/export", Object.assign(state.queryForm, { ids: selectObjs }), "mallCategory.xlsx")
|
||||||
}
|
}
|
||||||
|
|
||||||
// 多选事件
|
// 多选事件
|
||||||
const selectionChangHandle = (objs: { id: string }[]) => {
|
const selectionChangHandle = (objs: { id: string }[]) => {
|
||||||
selectObjs.value = objs.map(({ id }) => id);
|
selectObjs.value = objs.map(({ id }) => id)
|
||||||
multiple.value = !objs.length;
|
multiple.value = !objs.length
|
||||||
};
|
}
|
||||||
|
|
||||||
// 删除操作
|
// 删除操作
|
||||||
const handleDelete = async (ids: string[]) => {
|
const handleDelete = async (ids: string[]) => {
|
||||||
try {
|
try {
|
||||||
await useMessageBox().confirm('此操作将永久删除');
|
await useMessageBox().confirm("此操作将永久删除")
|
||||||
} catch {
|
} catch {
|
||||||
return;
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
await delObjs(ids);
|
await delObjs(ids)
|
||||||
getDataList();
|
getDataList()
|
||||||
useMessage().success('删除成功');
|
useMessage().success("删除成功")
|
||||||
} catch (err: any) {
|
} catch (err: any) {
|
||||||
useMessage().error(err.msg);
|
useMessage().error(err.msg)
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
|
|
||||||
defineExpose({
|
defineExpose({
|
||||||
treeData
|
treeData,
|
||||||
});
|
})
|
||||||
</script>
|
</script>
|
||||||
@@ -0,0 +1,294 @@
|
|||||||
|
<template>
|
||||||
|
<el-dialog :title="`绑定用户 - ${merchantInfo.name}`" v-model="visible"
|
||||||
|
:close-on-click-modal="false" draggable width="80%" top="5vh">
|
||||||
|
|
||||||
|
<!-- 搜索区域 -->
|
||||||
|
<div class="mb20">
|
||||||
|
<el-row :gutter="20">
|
||||||
|
<el-col :span="8">
|
||||||
|
<el-input v-model="searchForm.name" placeholder="请输入用户名称" clearable @keyup.enter="getUserList">
|
||||||
|
<template #prefix>
|
||||||
|
<el-icon><Search /></el-icon>
|
||||||
|
</template>
|
||||||
|
</el-input>
|
||||||
|
</el-col>
|
||||||
|
<el-col :span="8">
|
||||||
|
<el-input v-model="searchForm.phone" placeholder="请输入手机号" clearable @keyup.enter="getUserList">
|
||||||
|
<template #prefix>
|
||||||
|
<el-icon><Search /></el-icon>
|
||||||
|
</template>
|
||||||
|
</el-input>
|
||||||
|
</el-col>
|
||||||
|
<el-col :span="8">
|
||||||
|
<el-button type="primary" @click="getUserList">查询</el-button>
|
||||||
|
<el-button @click="resetSearch">重置</el-button>
|
||||||
|
</el-col>
|
||||||
|
</el-row>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<el-row :gutter="20">
|
||||||
|
<!-- 可选用户列表 -->
|
||||||
|
<el-col :span="12">
|
||||||
|
<div class="panel-title">可选用户</div>
|
||||||
|
<el-table
|
||||||
|
:data="availableUsers"
|
||||||
|
v-loading="userLoading"
|
||||||
|
height="400"
|
||||||
|
@selection-change="handleUserSelectionChange"
|
||||||
|
:row-key="row => row.userId">
|
||||||
|
<el-table-column type="selection" width="55" />
|
||||||
|
<el-table-column prop="name" label="姓名" show-overflow-tooltip />
|
||||||
|
<el-table-column prop="phone" label="手机号" show-overflow-tooltip />
|
||||||
|
</el-table>
|
||||||
|
<div class="mt10">
|
||||||
|
<el-button type="primary" @click="bindSelectedUsers" :disabled="selectedUsers.length === 0">
|
||||||
|
绑定选中用户
|
||||||
|
</el-button>
|
||||||
|
</div>
|
||||||
|
</el-col>
|
||||||
|
|
||||||
|
<!-- 已绑定用户列表 -->
|
||||||
|
<el-col :span="12">
|
||||||
|
<div class="panel-title">已绑定用户</div>
|
||||||
|
<el-table
|
||||||
|
:data="boundUsers"
|
||||||
|
v-loading="boundLoading"
|
||||||
|
height="400"
|
||||||
|
@selection-change="handleBoundUserSelectionChange"
|
||||||
|
:row-key="row => row.userId">
|
||||||
|
<el-table-column type="selection" width="55" />
|
||||||
|
<el-table-column prop="name" label="姓名" show-overflow-tooltip />
|
||||||
|
<el-table-column prop="phone" label="手机号" show-overflow-tooltip />
|
||||||
|
</el-table>
|
||||||
|
<div class="mt10">
|
||||||
|
<el-button type="danger" @click="batchUnbindUsers" :disabled="selectedBoundUsers.length === 0">
|
||||||
|
批量解绑
|
||||||
|
</el-button>
|
||||||
|
</div>
|
||||||
|
</el-col>
|
||||||
|
</el-row>
|
||||||
|
|
||||||
|
<template #footer>
|
||||||
|
<span class="dialog-footer">
|
||||||
|
<el-button @click="visible = false">关闭</el-button>
|
||||||
|
</span>
|
||||||
|
</template>
|
||||||
|
</el-dialog>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts" name="BindUserDialog">
|
||||||
|
import { useMessage } from "/@/hooks/message";
|
||||||
|
import { ElMessageBox } from 'element-plus';
|
||||||
|
import {
|
||||||
|
getUserSelectList,
|
||||||
|
getMerchantUsers,
|
||||||
|
batchBindUsers,
|
||||||
|
batchUnbindUsers as batchUnbindUsersApi
|
||||||
|
} from '/@/api/supermarket/mallMerchantUser';
|
||||||
|
import { Search } from '@element-plus/icons-vue';
|
||||||
|
|
||||||
|
const emit = defineEmits(['refresh']);
|
||||||
|
|
||||||
|
// 定义变量
|
||||||
|
const visible = ref(false);
|
||||||
|
const merchantInfo = ref<any>({});
|
||||||
|
const userLoading = ref(false);
|
||||||
|
const boundLoading = ref(false);
|
||||||
|
|
||||||
|
// 搜索表单
|
||||||
|
const searchForm = reactive({
|
||||||
|
name: '',
|
||||||
|
phone: ''
|
||||||
|
});
|
||||||
|
|
||||||
|
// 用户列表
|
||||||
|
const availableUsers = ref<any[]>([]);
|
||||||
|
const boundUsers = ref<any[]>([]);
|
||||||
|
const selectedUsers = ref<any[]>([]);
|
||||||
|
const selectedBoundUsers = ref<any[]>([]);
|
||||||
|
|
||||||
|
// 打开对话框
|
||||||
|
const openDialog = (merchant: any) => {
|
||||||
|
visible.value = true;
|
||||||
|
merchantInfo.value = merchant;
|
||||||
|
|
||||||
|
// 重置数据
|
||||||
|
availableUsers.value = [];
|
||||||
|
boundUsers.value = [];
|
||||||
|
selectedUsers.value = [];
|
||||||
|
selectedBoundUsers.value = [];
|
||||||
|
|
||||||
|
// 先获取已绑定用户,然后内部会调用getUserList过滤可选用户
|
||||||
|
getBoundUsers();
|
||||||
|
};
|
||||||
|
|
||||||
|
// 获取可选用户列表(从已获取的所有用户中过滤)
|
||||||
|
const getUserList = async () => {
|
||||||
|
try {
|
||||||
|
userLoading.value = true;
|
||||||
|
|
||||||
|
// 重新获取用户列表(支持搜索)
|
||||||
|
const res = await getUserSelectList({
|
||||||
|
name: searchForm.name,
|
||||||
|
phone: searchForm.phone,
|
||||||
|
current: 1,
|
||||||
|
size: 100
|
||||||
|
});
|
||||||
|
|
||||||
|
// 直接使用接口返回的数据格式
|
||||||
|
const allUsers = res.data || [];
|
||||||
|
console.log('可选用户接口返回的原始数据:', res);
|
||||||
|
console.log('获取到的用户数据:', allUsers);
|
||||||
|
console.log('用户数据长度:', allUsers.length);
|
||||||
|
|
||||||
|
// 过滤掉已绑定的用户
|
||||||
|
const boundUserIds = boundUsers.value.map(user => user.userId);
|
||||||
|
console.log('已绑定用户ID列表:', boundUserIds);
|
||||||
|
availableUsers.value = allUsers.filter((user: any) => !boundUserIds.includes(user.userId));
|
||||||
|
console.log('过滤后的可选用户:', availableUsers.value);
|
||||||
|
console.log('可选用户数据长度:', availableUsers.value.length);
|
||||||
|
} catch (err: any) {
|
||||||
|
useMessage().error(err.msg || '获取用户列表失败');
|
||||||
|
} finally {
|
||||||
|
userLoading.value = false;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// 获取已绑定用户列表
|
||||||
|
const getBoundUsers = async () => {
|
||||||
|
try {
|
||||||
|
boundLoading.value = true;
|
||||||
|
const res = await getMerchantUsers(merchantInfo.value.id);
|
||||||
|
console.log('已绑定用户接口返回的原始数据:', res);
|
||||||
|
|
||||||
|
// 已绑定用户接口返回的name和phone是null,需要从可选用户中获取
|
||||||
|
const boundUsersData = res.data || [];
|
||||||
|
console.log('已绑定用户原始数据:', boundUsersData);
|
||||||
|
|
||||||
|
// 先获取所有用户信息,用于匹配已绑定用户的姓名和手机号
|
||||||
|
const allUsersRes = await getUserSelectList({});
|
||||||
|
const allUsers = allUsersRes.data || [];
|
||||||
|
console.log('所有用户数据:', allUsers);
|
||||||
|
|
||||||
|
// 为已绑定用户补充姓名和手机号信息
|
||||||
|
boundUsers.value = boundUsersData.map((boundUser: any) => {
|
||||||
|
const userInfo = allUsers.find((user: any) => user.userId === boundUser.userId);
|
||||||
|
return {
|
||||||
|
...boundUser,
|
||||||
|
name: userInfo?.name || boundUser.name || '未知',
|
||||||
|
phone: userInfo?.phone || boundUser.phone || '未知'
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
console.log('处理后的已绑定用户数据:', boundUsers.value);
|
||||||
|
|
||||||
|
// 直接过滤可选用户,避免重复请求接口
|
||||||
|
const boundUserIds = boundUsers.value.map(user => user.userId);
|
||||||
|
console.log('已绑定用户ID列表:', boundUserIds);
|
||||||
|
availableUsers.value = allUsers.filter((user: any) => !boundUserIds.includes(user.userId));
|
||||||
|
console.log('过滤后的可选用户:', availableUsers.value);
|
||||||
|
} catch (err: any) {
|
||||||
|
useMessage().error(err.msg || '获取绑定用户失败');
|
||||||
|
} finally {
|
||||||
|
boundLoading.value = false;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// 重置搜索
|
||||||
|
const resetSearch = () => {
|
||||||
|
searchForm.name = '';
|
||||||
|
searchForm.phone = '';
|
||||||
|
getUserList();
|
||||||
|
};
|
||||||
|
|
||||||
|
// 用户选择变化
|
||||||
|
const handleUserSelectionChange = (selection: any[]) => {
|
||||||
|
selectedUsers.value = selection;
|
||||||
|
};
|
||||||
|
|
||||||
|
// 已绑定用户选择变化
|
||||||
|
const handleBoundUserSelectionChange = (selection: any[]) => {
|
||||||
|
selectedBoundUsers.value = selection;
|
||||||
|
};
|
||||||
|
|
||||||
|
// 绑定选中用户
|
||||||
|
const bindSelectedUsers = async () => {
|
||||||
|
if (selectedUsers.value.length === 0) {
|
||||||
|
useMessage().warning('请选择要绑定的用户');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
const bindData = {
|
||||||
|
merchantId: merchantInfo.value.id,
|
||||||
|
userIds: selectedUsers.value.map(user => user.userId)
|
||||||
|
};
|
||||||
|
|
||||||
|
await batchBindUsers(bindData);
|
||||||
|
useMessage().success('绑定成功');
|
||||||
|
|
||||||
|
// 刷新数据
|
||||||
|
getUserList();
|
||||||
|
getBoundUsers();
|
||||||
|
emit('refresh');
|
||||||
|
} catch (err: any) {
|
||||||
|
useMessage().error(err.msg || '绑定失败');
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// 批量解绑用户
|
||||||
|
const batchUnbindUsers = async () => {
|
||||||
|
if (selectedBoundUsers.value.length === 0) {
|
||||||
|
useMessage().warning('请选择要解绑的用户');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
await ElMessageBox.confirm(`确定要解绑选中的 ${selectedBoundUsers.value.length} 个用户吗?`, '提示', {
|
||||||
|
confirmButtonText: '确定',
|
||||||
|
cancelButtonText: '取消',
|
||||||
|
type: 'warning'
|
||||||
|
});
|
||||||
|
|
||||||
|
const unbindData = {
|
||||||
|
merchantId: merchantInfo.value.id,
|
||||||
|
userIds: selectedBoundUsers.value.map(user => user.userId)
|
||||||
|
};
|
||||||
|
|
||||||
|
await batchUnbindUsersApi(unbindData);
|
||||||
|
useMessage().success('批量解绑成功');
|
||||||
|
|
||||||
|
// 刷新数据
|
||||||
|
getUserList();
|
||||||
|
getBoundUsers();
|
||||||
|
emit('refresh');
|
||||||
|
} catch (err: any) {
|
||||||
|
if (err !== 'cancel') {
|
||||||
|
useMessage().error(err.msg || '批量解绑失败');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// 暴露方法
|
||||||
|
defineExpose({
|
||||||
|
openDialog
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.panel-title {
|
||||||
|
font-size: 16px;
|
||||||
|
font-weight: bold;
|
||||||
|
margin-bottom: 10px;
|
||||||
|
padding-bottom: 8px;
|
||||||
|
border-bottom: 1px solid #e4e7ed;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mt10 {
|
||||||
|
margin-top: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mb20 {
|
||||||
|
margin-bottom: 20px;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@@ -1,174 +1,217 @@
|
|||||||
<template>
|
<template>
|
||||||
<el-dialog :title="form.id ? '编辑' : '新增'" v-model="visible"
|
<el-dialog :title="form.id ? '编辑' : '新增'" v-model="visible" :close-on-click-modal="false" draggable>
|
||||||
:close-on-click-modal="false" draggable>
|
<el-form ref="dataFormRef" :model="form" :rules="dataRules" formDialogRef label-width="90px" v-loading="loading">
|
||||||
<el-form ref="dataFormRef" :model="form" :rules="dataRules" formDialogRef label-width="90px" v-loading="loading">
|
<el-row :gutter="24">
|
||||||
<el-row :gutter="24">
|
<el-col :span="12" class="mb20">
|
||||||
<el-col :span="12" class="mb20">
|
<el-form-item label="商户名称" prop="name">
|
||||||
<el-form-item label="商户名称" prop="name">
|
<el-input v-model="form.name" placeholder="请输入商户名称" />
|
||||||
<el-input v-model="form.name" placeholder="请输入商户名称"/>
|
</el-form-item>
|
||||||
</el-form-item>
|
</el-col>
|
||||||
</el-col>
|
|
||||||
|
|
||||||
<el-col :span="12" class="mb20">
|
<el-col :span="12" class="mb20">
|
||||||
<el-form-item label="商户简称" prop="shortName">
|
<el-form-item label="商户简称" prop="shortName">
|
||||||
<el-input v-model="form.shortName" placeholder="请输入商户简称"/>
|
<el-input v-model="form.shortName" placeholder="请输入商户简称" />
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
</el-col>
|
</el-col>
|
||||||
|
|
||||||
<el-col :span="12" class="mb20">
|
<el-col :span="12" class="mb20">
|
||||||
<el-form-item label="联系人" prop="contactName">
|
<el-form-item label="联系人" prop="contactName">
|
||||||
<el-input v-model="form.contactName" placeholder="请输入联系人"/>
|
<el-input v-model="form.contactName" placeholder="请输入联系人" />
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
</el-col>
|
</el-col>
|
||||||
|
|
||||||
<el-col :span="12" class="mb20">
|
<el-col :span="12" class="mb20">
|
||||||
<el-form-item label="联系电话" prop="contactPhone">
|
<el-form-item label="联系电话" prop="contactPhone">
|
||||||
<el-input v-model="form.contactPhone" placeholder="请输入联系电话"/>
|
<el-input v-model="form.contactPhone" placeholder="请输入联系电话" />
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
</el-col>
|
</el-col>
|
||||||
|
|
||||||
<el-col :span="12" class="mb20">
|
<!-- <el-col :span="12" class="mb20">-->
|
||||||
<el-form-item label="邮箱" prop="email">
|
<!-- <el-form-item label="邮箱" prop="email">-->
|
||||||
<el-input v-model="form.email" placeholder="请输入邮箱"/>
|
<!-- <el-input v-model="form.email" placeholder="请输入邮箱"/>-->
|
||||||
</el-form-item>
|
<!-- </el-form-item>-->
|
||||||
</el-col>
|
<!-- </el-col>-->
|
||||||
|
|
||||||
<el-col :span="12" class="mb20">
|
<el-col :span="12" class="mb20">
|
||||||
<el-form-item label="状态(1启用 0停用)" prop="status">
|
<el-form-item label="营业时间" prop="businessHours">
|
||||||
<el-radio-group v-model="form.status">
|
<el-time-picker
|
||||||
<el-radio :label="item.value" v-for="(item, index) in common_data_status" border :key="index">{{ item.label }}
|
v-model="businessHoursRange"
|
||||||
</el-radio>
|
is-range
|
||||||
</el-radio-group>
|
range-separator="至"
|
||||||
</el-form-item>
|
start-placeholder="开始时间"
|
||||||
</el-col>
|
end-placeholder="结束时间"
|
||||||
|
format="HH:mm"
|
||||||
|
value-format="HH:mm"
|
||||||
|
placeholder="请选择营业时间"
|
||||||
|
/>
|
||||||
|
</el-form-item>
|
||||||
|
</el-col>
|
||||||
|
|
||||||
<el-col :span="12" class="mb20">
|
<el-col :span="12" class="mb20">
|
||||||
<el-form-item label="营业执照号" prop="licenseNo">
|
<el-form-item label="状态" prop="status">
|
||||||
<el-input v-model="form.licenseNo" placeholder="请输入营业执照号"/>
|
<el-radio-group v-model="form.status">
|
||||||
</el-form-item>
|
<el-radio :label="item.value" v-for="(item, index) in common_data_status" border :key="index">{{ item.label }} </el-radio>
|
||||||
</el-col>
|
</el-radio-group>
|
||||||
|
</el-form-item>
|
||||||
|
</el-col>
|
||||||
|
|
||||||
<el-col :span="12" class="mb20">
|
<el-col :span="12" class="mb20">
|
||||||
<el-form-item label="详细地址" prop="address">
|
<el-form-item label="营业执照号" prop="licenseNo">
|
||||||
<el-input type="textarea" v-model="form.address" placeholder="请输入详细地址"/>
|
<el-input v-model="form.licenseNo" placeholder="请输入营业执照号" />
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
</el-col>
|
</el-col>
|
||||||
|
|
||||||
<el-col :span="12" class="mb20">
|
<el-col :span="12" class="mb20">
|
||||||
<el-form-item label="商户图片URL(逗号分隔)" prop="images">
|
<el-form-item label="详细地址" prop="address">
|
||||||
<upload-img v-model="form.images"></upload-img>
|
<el-input type="textarea" v-model="form.address" placeholder="请输入详细地址" />
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
</el-col>
|
</el-col>
|
||||||
|
|
||||||
<el-col :span="12" class="mb20">
|
<el-col :span="12" class="mb20">
|
||||||
<el-form-item label="备注" prop="remark">
|
<el-form-item label="商户图片" prop="images">
|
||||||
<el-input v-model="form.remark" placeholder="请输入备注"/>
|
<upload-img v-model:imageUrl="form.images"></upload-img>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
</el-col>
|
</el-col>
|
||||||
|
|
||||||
<el-col :span="12" class="mb20">
|
|
||||||
<el-form-item label="部门ID" prop="deptId">
|
|
||||||
<el-input v-model="form.deptId" placeholder="请输入部门ID"/>
|
|
||||||
</el-form-item>
|
|
||||||
</el-col>
|
|
||||||
|
|
||||||
|
<el-col :span="12" class="mb20">
|
||||||
|
<el-form-item label="备注" prop="remark">
|
||||||
|
<el-input type="textarea" v-model="form.remark" placeholder="请输入备注" />
|
||||||
|
</el-form-item>
|
||||||
|
</el-col>
|
||||||
</el-row>
|
</el-row>
|
||||||
</el-form>
|
</el-form>
|
||||||
<template #footer>
|
<template #footer>
|
||||||
<span class="dialog-footer">
|
<span class="dialog-footer">
|
||||||
<el-button @click="visible = false">取消</el-button>
|
<el-button @click="visible = false">取消</el-button>
|
||||||
<el-button type="primary" @click="onSubmit" :disabled="loading">确认</el-button>
|
<el-button type="primary" @click="onSubmit" :disabled="loading">确认</el-button>
|
||||||
</span>
|
</span>
|
||||||
</template>
|
</template>
|
||||||
</el-dialog>
|
</el-dialog>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts" name="MallMerchantDialog">
|
<script setup lang="ts" name="MallMerchantDialog">
|
||||||
import { useDict } from '/@/hooks/dict';
|
import { useDict } from "/@/hooks/dict"
|
||||||
import { useMessage } from "/@/hooks/message";
|
import { useMessage } from "/@/hooks/message"
|
||||||
import { getObj, addObj, putObj } from '/@/api/supermarket/mallMerchant'
|
import { getObj, addObj, putObj } from "/@/api/supermarket/mallMerchant"
|
||||||
import { rule } from '/@/utils/validate';
|
import { rule } from "/@/utils/validate"
|
||||||
const emit = defineEmits(['refresh']);
|
import { ref, reactive, nextTick, watch } from "vue"
|
||||||
|
const emit = defineEmits(["refresh"])
|
||||||
|
|
||||||
// 定义变量内容
|
// 定义变量内容
|
||||||
const dataFormRef = ref();
|
const dataFormRef = ref()
|
||||||
const visible = ref(false)
|
const visible = ref(false)
|
||||||
const loading = ref(false)
|
const loading = ref(false)
|
||||||
// 定义字典
|
// 定义字典
|
||||||
const { common_data_status } = useDict('common_data_status')
|
const { common_data_status } = useDict("common_data_status")
|
||||||
|
|
||||||
// 提交表单数据
|
// 提交表单数据
|
||||||
const form = reactive({
|
const form = reactive({
|
||||||
id:'',
|
id: "",
|
||||||
name: '',
|
name: "",
|
||||||
shortName: '',
|
shortName: "",
|
||||||
contactName: '',
|
contactName: "",
|
||||||
contactPhone: '',
|
contactPhone: "",
|
||||||
email: '',
|
email: "",
|
||||||
status: '',
|
businessHours: "", // 营业时间
|
||||||
licenseNo: '',
|
status: 1, // 默认正常状态
|
||||||
address: '',
|
licenseNo: "",
|
||||||
images: '',
|
address: "",
|
||||||
remark: '',
|
images: "",
|
||||||
deptId: '',
|
remark: "",
|
||||||
});
|
deptId: "",
|
||||||
|
})
|
||||||
|
|
||||||
|
// 营业时间范围选择器
|
||||||
|
const businessHoursRange = ref<[string, string] | null>(null)
|
||||||
|
|
||||||
|
// 监听营业时间范围变化,转换为数据库格式
|
||||||
|
watch(
|
||||||
|
businessHoursRange,
|
||||||
|
(newRange) => {
|
||||||
|
if (newRange && newRange.length === 2) {
|
||||||
|
form.businessHours = `${newRange[0]}-${newRange[1]}`
|
||||||
|
} else {
|
||||||
|
form.businessHours = ""
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{ immediate: true },
|
||||||
|
)
|
||||||
|
|
||||||
// 定义校验规则
|
// 定义校验规则
|
||||||
const dataRules = ref({
|
const dataRules = ref({
|
||||||
name: [{required: true, message: '商户名称不能为空', trigger: 'blur'}],
|
name: [{ required: true, message: "商户名称不能为空", trigger: "blur" }],
|
||||||
contactName: [{required: true, message: '联系人不能为空', trigger: 'blur'}],
|
contactName: [{ required: true, message: "联系人不能为空", trigger: "blur" }],
|
||||||
contactPhone: [{required: true, message: '联系电话不能为空', trigger: 'blur'}, { validator: rule.mobilePhone, trigger: 'blur' }],
|
contactPhone: [
|
||||||
|
{ required: true, message: "联系电话不能为空", trigger: "blur" },
|
||||||
|
{ validator: rule.mobilePhone, trigger: "blur" },
|
||||||
|
],
|
||||||
|
businessHours: [{ required: true, message: "营业时间不能为空", trigger: "change" }],
|
||||||
})
|
})
|
||||||
|
|
||||||
// 打开弹窗
|
// 打开弹窗
|
||||||
const openDialog = (id: string) => {
|
const openDialog = (id: string) => {
|
||||||
visible.value = true
|
visible.value = true
|
||||||
form.id = ''
|
form.id = ""
|
||||||
|
|
||||||
// 重置表单数据
|
// 重置表单数据
|
||||||
nextTick(() => {
|
nextTick(() => {
|
||||||
dataFormRef.value?.resetFields();
|
dataFormRef.value?.resetFields()
|
||||||
});
|
// 新增时设置默认状态为正常
|
||||||
|
if (!id) {
|
||||||
|
form.status = 1
|
||||||
|
}
|
||||||
|
// 重置营业时间
|
||||||
|
businessHoursRange.value = null
|
||||||
|
})
|
||||||
|
|
||||||
// 获取mallMerchant信息
|
// 获取mallMerchant信息
|
||||||
if (id) {
|
if (id) {
|
||||||
form.id = id
|
form.id = id
|
||||||
getmallMerchantData(id)
|
getmallMerchantData(id)
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
|
|
||||||
// 提交
|
// 提交
|
||||||
const onSubmit = async () => {
|
const onSubmit = async () => {
|
||||||
const valid = await dataFormRef.value.validate().catch(() => {});
|
const valid = await dataFormRef.value.validate().catch(() => {})
|
||||||
if (!valid) return false;
|
if (!valid) return false
|
||||||
|
|
||||||
try {
|
try {
|
||||||
loading.value = true;
|
loading.value = true
|
||||||
form.id ? await putObj(form) : await addObj(form);
|
form.id ? await putObj(form) : await addObj(form)
|
||||||
useMessage().success(form.id ? '修改成功' : '添加成功');
|
useMessage().success(form.id ? "修改成功" : "添加成功")
|
||||||
visible.value = false;
|
visible.value = false
|
||||||
emit('refresh');
|
emit("refresh")
|
||||||
} catch (err: any) {
|
} catch (err: any) {
|
||||||
useMessage().error(err.msg);
|
useMessage().error(err.msg)
|
||||||
} finally {
|
} finally {
|
||||||
loading.value = false;
|
loading.value = false
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
|
|
||||||
|
|
||||||
// 初始化表单数据
|
// 初始化表单数据
|
||||||
const getmallMerchantData = (id: string) => {
|
const getmallMerchantData = (id: string) => {
|
||||||
// 获取数据
|
// 获取数据
|
||||||
loading.value = true
|
loading.value = true
|
||||||
getObj(id).then((res: any) => {
|
getObj(id)
|
||||||
Object.assign(form, res.data)
|
.then((res: any) => {
|
||||||
}).finally(() => {
|
Object.assign(form, res.data)
|
||||||
loading.value = false
|
|
||||||
})
|
// 处理营业时间回显
|
||||||
};
|
if (res.data.businessHours) {
|
||||||
|
const timeRange = res.data.businessHours.split("-")
|
||||||
|
if (timeRange.length === 2) {
|
||||||
|
businessHoursRange.value = [timeRange[0], timeRange[1]]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.finally(() => {
|
||||||
|
loading.value = false
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
// 暴露变量
|
// 暴露变量
|
||||||
defineExpose({
|
defineExpose({
|
||||||
openDialog
|
openDialog,
|
||||||
});
|
})
|
||||||
</script>
|
</script>
|
||||||
@@ -1,91 +1,128 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="layout-padding">
|
<div class="layout-padding">
|
||||||
<div class="layout-padding-auto layout-padding-view">
|
<div class="layout-padding-auto layout-padding-view">
|
||||||
<el-row v-show="showSearch">
|
<el-row v-show="showSearch">
|
||||||
<el-form :model="state.queryForm" ref="queryRef" :inline="true" @keyup.enter="getDataList">
|
<el-form :model="state.queryForm" ref="queryRef" :inline="true" @keyup.enter="getDataList">
|
||||||
<el-form-item label="商户名称" prop="name" >
|
<el-form-item label="商户名称" prop="name">
|
||||||
<el-input placeholder="请输入商户名称" v-model="state.queryForm.name" />
|
<el-input placeholder="请输入商户名称" v-model="state.queryForm.name" />
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item label="联系人" prop="contactName" >
|
<el-form-item label="联系人" prop="contactName">
|
||||||
<el-input placeholder="请输入联系人" v-model="state.queryForm.contactName" />
|
<el-input placeholder="请输入联系人" v-model="state.queryForm.contactName" />
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item label="联系电话" prop="contactPhone" >
|
<el-form-item label="联系电话" prop="contactPhone">
|
||||||
<el-input placeholder="请输入联系电话" v-model="state.queryForm.contactPhone" />
|
<el-input placeholder="请输入联系电话" v-model="state.queryForm.contactPhone" />
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item>
|
<el-form-item>
|
||||||
<el-button icon="search" type="primary" @click="getDataList">
|
<el-button icon="search" type="primary" @click="getDataList"> 查询 </el-button>
|
||||||
查询
|
<el-button icon="Refresh" @click="resetQuery">重置</el-button>
|
||||||
</el-button>
|
</el-form-item>
|
||||||
<el-button icon="Refresh" @click="resetQuery">重置</el-button>
|
</el-form>
|
||||||
</el-form-item>
|
</el-row>
|
||||||
</el-form>
|
<el-row>
|
||||||
</el-row>
|
<div class="mb8" style="width: 100%">
|
||||||
<el-row>
|
<el-button
|
||||||
<div class="mb8" style="width: 100%">
|
icon="folder-add"
|
||||||
<el-button icon="folder-add" type="primary" class="ml10" @click="formDialogRef.openDialog()"
|
type="primary"
|
||||||
v-auth="'supermarket_mallMerchant_add'">
|
class="ml10"
|
||||||
新 增
|
@click="formDialogRef.openDialog()"
|
||||||
</el-button>
|
v-auth="'supermarket_mallMerchant_add'"
|
||||||
<el-button plain :disabled="multiple" icon="Delete" type="primary"
|
>
|
||||||
v-auth="'supermarket_mallMerchant_del'" @click="handleDelete(selectObjs)">
|
新 增
|
||||||
删除
|
</el-button>
|
||||||
</el-button>
|
<el-button
|
||||||
<right-toolbar v-model:showSearch="showSearch" :export="'supermarket_mallMerchant_export'"
|
plain
|
||||||
@exportExcel="exportExcel" class="ml10 mr20" style="float: right;"
|
:disabled="multiple"
|
||||||
@queryTable="getDataList"></right-toolbar>
|
icon="Delete"
|
||||||
</div>
|
type="primary"
|
||||||
</el-row>
|
v-auth="'supermarket_mallMerchant_del'"
|
||||||
<el-table :data="state.dataList" v-loading="state.loading" border
|
@click="handleDelete(selectObjs)"
|
||||||
:cell-style="tableStyle.cellStyle" :header-cell-style="tableStyle.headerCellStyle"
|
>
|
||||||
|
删 除
|
||||||
|
</el-button>
|
||||||
|
<right-toolbar
|
||||||
|
v-model:showSearch="showSearch"
|
||||||
|
:export="'supermarket_mallMerchant_export'"
|
||||||
|
@exportExcel="exportExcel"
|
||||||
|
class="ml10 mr20"
|
||||||
|
style="float: right"
|
||||||
|
@queryTable="getDataList"
|
||||||
|
></right-toolbar>
|
||||||
|
</div>
|
||||||
|
</el-row>
|
||||||
|
<el-table
|
||||||
|
:data="state.dataList"
|
||||||
|
v-loading="state.loading"
|
||||||
|
border
|
||||||
|
:cell-style="tableStyle.cellStyle"
|
||||||
|
:header-cell-style="tableStyle.headerCellStyle"
|
||||||
@selection-change="selectionChangHandle"
|
@selection-change="selectionChangHandle"
|
||||||
@sort-change="sortChangeHandle">
|
@sort-change="sortChangeHandle"
|
||||||
<el-table-column type="selection" width="40" align="center" />
|
>
|
||||||
<el-table-column type="index" label="#" width="40" />
|
<el-table-column type="selection" width="40" align="center" />
|
||||||
<el-table-column prop="name" label="商户名称" show-overflow-tooltip/>
|
<el-table-column type="index" label="#" width="40" />
|
||||||
<el-table-column prop="shortName" label="商户简称" show-overflow-tooltip/>
|
<el-table-column prop="name" label="商户名称" show-overflow-tooltip />
|
||||||
<el-table-column prop="contactName" label="联系人" show-overflow-tooltip/>
|
<el-table-column prop="shortName" label="商户简称" show-overflow-tooltip />
|
||||||
<el-table-column prop="contactPhone" label="联系电话" show-overflow-tooltip/>
|
<el-table-column prop="contactName" label="联系人" show-overflow-tooltip />
|
||||||
<el-table-column prop="email" label="邮箱" show-overflow-tooltip/>
|
<el-table-column prop="contactPhone" label="联系电话" show-overflow-tooltip />
|
||||||
<el-table-column prop="status" label="状态(1启用 0停用)" show-overflow-tooltip>
|
<el-table-column prop="businessHours" label="营业时间" show-overflow-tooltip />
|
||||||
<template #default="scope">
|
<!-- <el-table-column prop="email" label="邮箱" show-overflow-tooltip/>-->
|
||||||
<dict-tag :options="common_data_status" :value="scope.row.status"></dict-tag>
|
<el-table-column prop="status" label="状态" show-overflow-tooltip>
|
||||||
</template>
|
<template #default="scope">
|
||||||
</el-table-column>
|
<dict-tag :options="common_data_status" :value="scope.row.status"></dict-tag>
|
||||||
<el-table-column prop="licenseNo" label="营业执照号" show-overflow-tooltip/>
|
</template>
|
||||||
<el-table-column prop="address" label="详细地址" show-overflow-tooltip/>
|
</el-table-column>
|
||||||
<el-table-column prop="images" label="商户图片URL(逗号分隔)" show-overflow-tooltip/>
|
<el-table-column prop="licenseNo" label="营业执照号" show-overflow-tooltip />
|
||||||
<el-table-column prop="remark" label="备注" show-overflow-tooltip/>
|
<el-table-column prop="address" label="详细地址" show-overflow-tooltip />
|
||||||
<el-table-column prop="deptId" label="部门ID" show-overflow-tooltip/>
|
<el-table-column prop="images" label="商户图片" show-overflow-tooltip>
|
||||||
<el-table-column label="操作" width="150">
|
<template #default="scope">
|
||||||
<template #default="scope">
|
<preview-image :src="scope.row.images" />
|
||||||
<el-button icon="edit-pen" text type="primary" v-auth="'supermarket_mallMerchant_edit'"
|
</template>
|
||||||
@click="formDialogRef.openDialog(scope.row.id)">编辑</el-button>
|
</el-table-column>
|
||||||
<el-button icon="delete" text type="primary" v-auth="'supermarket_mallMerchant_del'" @click="handleDelete([scope.row.id])">删除</el-button>
|
<el-table-column prop="remark" label="备注" show-overflow-tooltip />
|
||||||
</template>
|
<el-table-column label="操作" width="200">
|
||||||
</el-table-column>
|
<template #default="scope">
|
||||||
</el-table>
|
<el-button
|
||||||
<pagination @size-change="sizeChangeHandle" @current-change="currentChangeHandle" v-bind="state.pagination" />
|
icon="edit-pen"
|
||||||
</div>
|
text
|
||||||
|
type="primary"
|
||||||
|
v-auth="'supermarket_mallMerchant_edit'"
|
||||||
|
@click="formDialogRef.openDialog(scope.row.id)"
|
||||||
|
>编辑</el-button
|
||||||
|
>
|
||||||
|
<el-button icon="user" text type="success" @click="handleBindUsers(scope.row)">绑定用户</el-button>
|
||||||
|
<el-button icon="delete" text type="primary" v-auth="'supermarket_mallMerchant_del'" @click="handleDelete([scope.row.id])"
|
||||||
|
>删除</el-button
|
||||||
|
>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
</el-table>
|
||||||
|
<pagination @size-change="sizeChangeHandle" @current-change="currentChangeHandle" v-bind="state.pagination" />
|
||||||
|
</div>
|
||||||
|
|
||||||
<!-- 编辑、新增 -->
|
<!-- 编辑、新增 -->
|
||||||
<form-dialog ref="formDialogRef" @refresh="getDataList(false)" />
|
<form-dialog ref="formDialogRef" @refresh="getDataList(false)" />
|
||||||
|
|
||||||
</div>
|
<!-- 绑定用户对话框 -->
|
||||||
|
<bind-user-dialog ref="bindUserDialogRef" @refresh="getDataList(false)" />
|
||||||
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts" name="systemMallMerchant">
|
<script setup lang="ts" name="systemMallMerchant">
|
||||||
import { BasicTableProps, useTable } from "/@/hooks/table";
|
import { defineAsyncComponent } from "vue"
|
||||||
import { fetchList, delObjs } from "/@/api/supermarket/mallMerchant";
|
import { BasicTableProps, useTable } from "/@/hooks/table"
|
||||||
import { useMessage, useMessageBox } from "/@/hooks/message";
|
import { fetchList, delObjs } from "/@/api/supermarket/mallMerchant"
|
||||||
import { useDict } from '/@/hooks/dict';
|
import { useMessage, useMessageBox } from "/@/hooks/message"
|
||||||
|
import { useDict } from "/@/hooks/dict"
|
||||||
|
|
||||||
// 引入组件
|
// 引入组件
|
||||||
const FormDialog = defineAsyncComponent(() => import('./form.vue'));
|
const FormDialog = defineAsyncComponent(() => import("./form.vue"))
|
||||||
|
const BindUserDialog = defineAsyncComponent(() => import("./bindUser.vue"))
|
||||||
// 定义查询字典
|
// 定义查询字典
|
||||||
|
|
||||||
const { common_data_status } = useDict('common_data_status')
|
const { common_data_status } = useDict("common_data_status")
|
||||||
// 定义变量内容
|
// 定义变量内容
|
||||||
const formDialogRef = ref()
|
const formDialogRef = ref()
|
||||||
|
const bindUserDialogRef = ref()
|
||||||
// 搜索变量
|
// 搜索变量
|
||||||
const queryRef = ref()
|
const queryRef = ref()
|
||||||
const showSearch = ref(true)
|
const showSearch = ref(true)
|
||||||
@@ -94,54 +131,52 @@ const selectObjs = ref([]) as any
|
|||||||
const multiple = ref(true)
|
const multiple = ref(true)
|
||||||
|
|
||||||
const state: BasicTableProps = reactive<BasicTableProps>({
|
const state: BasicTableProps = reactive<BasicTableProps>({
|
||||||
queryForm: {},
|
queryForm: {},
|
||||||
pageList: fetchList
|
pageList: fetchList,
|
||||||
})
|
})
|
||||||
|
|
||||||
// table hook
|
// table hook
|
||||||
const {
|
const { getDataList, currentChangeHandle, sizeChangeHandle, sortChangeHandle, downBlobFile, tableStyle } = useTable(state)
|
||||||
getDataList,
|
|
||||||
currentChangeHandle,
|
|
||||||
sizeChangeHandle,
|
|
||||||
sortChangeHandle,
|
|
||||||
downBlobFile,
|
|
||||||
tableStyle
|
|
||||||
} = useTable(state)
|
|
||||||
|
|
||||||
// 清空搜索条件
|
// 清空搜索条件
|
||||||
const resetQuery = () => {
|
const resetQuery = () => {
|
||||||
// 清空搜索条件
|
// 清空搜索条件
|
||||||
queryRef.value?.resetFields()
|
queryRef.value?.resetFields()
|
||||||
// 清空多选
|
// 清空多选
|
||||||
selectObjs.value = []
|
selectObjs.value = []
|
||||||
getDataList()
|
getDataList()
|
||||||
}
|
}
|
||||||
|
|
||||||
// 导出excel
|
// 导出excel
|
||||||
const exportExcel = () => {
|
const exportExcel = () => {
|
||||||
downBlobFile('/supermarket/mallMerchant/export', Object.assign(state.queryForm, { ids: selectObjs }), 'mallMerchant.xlsx')
|
downBlobFile("/supermarket/mallMerchant/export", Object.assign(state.queryForm, { ids: selectObjs }), "mallMerchant.xlsx")
|
||||||
}
|
}
|
||||||
|
|
||||||
// 多选事件
|
// 多选事件
|
||||||
const selectionChangHandle = (objs: { id: string }[]) => {
|
const selectionChangHandle = (objs: { id: string }[]) => {
|
||||||
selectObjs.value = objs.map(({ id }) => id);
|
selectObjs.value = objs.map(({ id }) => id)
|
||||||
multiple.value = !objs.length;
|
multiple.value = !objs.length
|
||||||
};
|
}
|
||||||
|
|
||||||
// 删除操作
|
// 删除操作
|
||||||
const handleDelete = async (ids: string[]) => {
|
const handleDelete = async (ids: string[]) => {
|
||||||
try {
|
try {
|
||||||
await useMessageBox().confirm('此操作将永久删除');
|
await useMessageBox().confirm("此操作将永久删除")
|
||||||
} catch {
|
} catch {
|
||||||
return;
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
await delObjs(ids);
|
await delObjs(ids)
|
||||||
getDataList();
|
getDataList()
|
||||||
useMessage().success('删除成功');
|
useMessage().success("删除成功")
|
||||||
} catch (err: any) {
|
} catch (err: any) {
|
||||||
useMessage().error(err.msg);
|
useMessage().error(err.msg)
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
</script>
|
|
||||||
|
// 绑定用户操作
|
||||||
|
const handleBindUsers = (merchant: any) => {
|
||||||
|
bindUserDialogRef.value?.openDialog(merchant)
|
||||||
|
}
|
||||||
|
</script>
|
||||||
@@ -1,219 +1,786 @@
|
|||||||
<template>
|
<template>
|
||||||
<el-dialog :title="form.id ? '编辑' : '新增'" v-model="visible"
|
<el-dialog :title="form.id ? '编辑商品' : '新增商品'" v-model="visible" :close-on-click-modal="false" draggable width="90%">
|
||||||
:close-on-click-modal="false" draggable>
|
<el-form ref="dataFormRef" :model="form" :rules="dataRules" formDialogRef label-width="120px" v-loading="loading">
|
||||||
<el-form ref="dataFormRef" :model="form" :rules="dataRules" formDialogRef label-width="90px" v-loading="loading">
|
<!-- 基本信息 -->
|
||||||
<el-row :gutter="24">
|
<el-tabs v-model="activeTab" type="border-card">
|
||||||
<el-col :span="12" class="mb20">
|
<el-tab-pane label="基本信息" name="basic">
|
||||||
<el-form-item label="商户ID" prop="merchantId">
|
<el-row :gutter="24">
|
||||||
<el-select v-model="form.merchantId" placeholder="请选择商户ID">
|
<el-col :span="12" class="mb20">
|
||||||
<el-option label="请选择">0</el-option>
|
<el-form-item label="商户" prop="merchantId" required>
|
||||||
</el-select>
|
<el-select v-model="form.merchantId" placeholder="请选择商户" clearable @change="onMerchantChange">
|
||||||
</el-form-item>
|
<el-option v-for="merchant in merchantOptions" :key="merchant.value" :label="merchant.label" :value="merchant.value" />
|
||||||
</el-col>
|
</el-select>
|
||||||
|
</el-form-item>
|
||||||
|
</el-col>
|
||||||
|
|
||||||
<el-col :span="12" class="mb20">
|
<el-col :span="12" class="mb20">
|
||||||
<el-form-item label="类目ID" prop="categoryId">
|
<el-form-item label="商品分类" prop="categoryId" required>
|
||||||
<el-select v-model="form.categoryId" placeholder="请选择类目ID">
|
<el-cascader
|
||||||
<el-option label="请选择">0</el-option>
|
v-model="form.categoryId"
|
||||||
</el-select>
|
:options="categoryOptions"
|
||||||
</el-form-item>
|
:props="{ value: 'id', label: 'name', children: 'children', checkStrictly: true }"
|
||||||
</el-col>
|
:disabled="!form.merchantId"
|
||||||
|
clearable
|
||||||
|
placeholder="请先选择商户"
|
||||||
|
/>
|
||||||
|
</el-form-item>
|
||||||
|
</el-col>
|
||||||
|
|
||||||
<el-col :span="12" class="mb20">
|
<el-col :span="24" class="mb20">
|
||||||
<el-form-item label="商品标题" prop="title">
|
<el-form-item label="商品标题" prop="title">
|
||||||
<el-input v-model="form.title" placeholder="请输入商品标题"/>
|
<el-input v-model="form.title" placeholder="请输入商品标题" maxlength="100" show-word-limit />
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
</el-col>
|
</el-col>
|
||||||
|
|
||||||
<el-col :span="12" class="mb20">
|
<el-col :span="12" class="mb20">
|
||||||
<el-form-item label="副标题" prop="subTitle">
|
<el-form-item label="计量单位" prop="unit">
|
||||||
<el-input v-model="form.subTitle" placeholder="请输入副标题"/>
|
<el-input v-model="form.unit" placeholder="请输入计量单位" />
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
</el-col>
|
</el-col>
|
||||||
|
|
||||||
<el-col :span="12" class="mb20">
|
<el-col :span="12" class="mb20">
|
||||||
<el-form-item label="品牌" prop="brand">
|
<el-form-item label="定价方式" prop="priceType">
|
||||||
<el-input v-model="form.brand" placeholder="请输入品牌"/>
|
<el-radio-group v-model="form.priceType" @change="onPriceTypeChange">
|
||||||
</el-form-item>
|
<el-radio :label="1">多SKU模式</el-radio>
|
||||||
</el-col>
|
<el-radio :label="2">单价SPU模式</el-radio>
|
||||||
|
</el-radio-group>
|
||||||
|
</el-form-item>
|
||||||
|
</el-col>
|
||||||
|
|
||||||
<el-col :span="12" class="mb20">
|
<el-col :span="12" class="mb20">
|
||||||
<el-form-item label="主图" prop="coverImage">
|
<el-form-item label="状态" prop="status">
|
||||||
<el-input v-model="form.coverImage" placeholder="请输入主图"/>
|
<el-radio-group v-model="form.status">
|
||||||
</el-form-item>
|
<el-radio label="0">上架</el-radio>
|
||||||
</el-col>
|
<el-radio label="1">下架</el-radio>
|
||||||
|
</el-radio-group>
|
||||||
|
</el-form-item>
|
||||||
|
</el-col>
|
||||||
|
|
||||||
<el-col :span="12" class="mb20">
|
<!-- 单价SPU模式的价格设置 -->
|
||||||
<el-form-item label="SPU轮播图URL(逗号分隔,按顺序)" prop="carouselImages">
|
<template v-if="form.priceType === 2">
|
||||||
<el-input v-model="form.carouselImages" placeholder="请输入SPU轮播图URL(逗号分隔,按顺序)"/>
|
<el-col :span="12" class="mb20">
|
||||||
</el-form-item>
|
<el-form-item label="SPU售价" prop="spuPrice">
|
||||||
</el-col>
|
<el-input-number v-model="form.spuPrice" :precision="2" :min="0" placeholder="请输入SPU售价" style="width: 100%" />
|
||||||
|
<span class="price-tip">单位:元</span>
|
||||||
|
</el-form-item>
|
||||||
|
</el-col>
|
||||||
|
|
||||||
<el-col :span="12" class="mb20">
|
<el-col :span="12" class="mb20">
|
||||||
<el-form-item label="定价方式(1多SKU 2单价SPU)" prop="priceType">
|
<el-form-item label="划线价" prop="originalPrice">
|
||||||
<el-input v-model="form.priceType" placeholder="请输入定价方式(1多SKU 2单价SPU)"/>
|
<el-input-number v-model="form.originalPrice" :precision="2" :min="0" placeholder="请输入划线价" style="width: 100%" />
|
||||||
</el-form-item>
|
<span class="price-tip">单位:元</span>
|
||||||
</el-col>
|
</el-form-item>
|
||||||
|
</el-col>
|
||||||
|
</template>
|
||||||
|
|
||||||
<el-col :span="12" class="mb20">
|
<el-col :span="12" class="mb20">
|
||||||
<el-form-item label="SPU售价(当price_type=2有效)" prop="spuPrice">
|
<el-form-item label="开售时间" prop="saleStartTime">
|
||||||
<el-input v-model="form.spuPrice" placeholder="请输入SPU售价(当price_type=2有效)"/>
|
<el-date-picker v-model="form.saleStartTime" type="datetime" placeholder="请选择开售时间" style="width: 100%" />
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
</el-col>
|
</el-col>
|
||||||
|
|
||||||
<el-col :span="12" class="mb20">
|
<el-col :span="12" class="mb20">
|
||||||
<el-form-item label="划线价" prop="originalPrice">
|
<el-form-item label="停售时间" prop="saleEndTime">
|
||||||
<el-input v-model="form.originalPrice" placeholder="请输入划线价"/>
|
<el-date-picker v-model="form.saleEndTime" type="datetime" placeholder="请选择停售时间" style="width: 100%" />
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
</el-col>
|
</el-col>
|
||||||
|
|
||||||
<el-col :span="12" class="mb20">
|
<el-col :span="24" class="mb20">
|
||||||
<el-form-item label="总库存(冗余)" prop="totalStock">
|
<el-form-item label="主图" prop="coverImage">
|
||||||
<el-input v-model="form.totalStock" placeholder="请输入总库存(冗余)"/>
|
<upload-img v-model:imageUrl="form.coverImage" />
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
</el-col>
|
</el-col>
|
||||||
|
|
||||||
<el-col :span="12" class="mb20">
|
<el-col :span="24" class="mb20">
|
||||||
<el-form-item label="计量单位" prop="unit">
|
<el-form-item label="轮播图" prop="carouselImages">
|
||||||
<el-input v-model="form.unit" placeholder="请输入计量单位"/>
|
<upload-img v-model:imageUrl="form.carouselImages" />
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
</el-col>
|
</el-col>
|
||||||
|
|
||||||
<el-col :span="12" class="mb20">
|
<el-col :span="24" class="mb20">
|
||||||
<el-form-item label="状态(1上架 0下架)" prop="status">
|
<el-form-item label="详情描述" prop="description">
|
||||||
<el-input v-model="form.status" placeholder="请输入状态(1上架 0下架)"/>
|
<editor v-if="visible" v-model:get-html="form.description" placeholder="请输入详情描述" />
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
</el-col>
|
</el-col>
|
||||||
|
</el-row>
|
||||||
|
</el-tab-pane>
|
||||||
|
|
||||||
<el-col :span="12" class="mb20">
|
<!-- SKU信息 -->
|
||||||
<el-form-item label="开售时间" prop="saleStartTime">
|
<el-tab-pane label="SKU信息" name="sku" v-if="form.priceType === 1">
|
||||||
<el-input v-model="form.saleStartTime" placeholder="请输入开售时间"/>
|
<div class="sku-header">
|
||||||
</el-form-item>
|
<el-button type="primary" @click="addSku" :disabled="loading">
|
||||||
</el-col>
|
<el-icon><Plus /></el-icon>
|
||||||
|
添加SKU
|
||||||
|
</el-button>
|
||||||
|
<span class="sku-tip">多SKU模式:支持不同规格的商品(如不同颜色、尺寸、配置等)</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
<el-col :span="12" class="mb20">
|
<div class="sku-table-container">
|
||||||
<el-form-item label="停售时间" prop="saleEndTime">
|
<el-table :data="form.skuList" border class="sku-table" v-loading="loading">
|
||||||
<el-input v-model="form.saleEndTime" placeholder="请输入停售时间"/>
|
<el-table-column type="index" label="#" width="60" align="center" />
|
||||||
</el-form-item>
|
|
||||||
</el-col>
|
|
||||||
|
|
||||||
<el-col :span="12" class="mb20">
|
<el-table-column label="SKU编码" width="140" align="center">
|
||||||
<el-form-item label="详情描述(HTML/文本)" prop="description">
|
<template #header> <span class="required">*</span> SKU编码 </template>
|
||||||
<editor v-if="visible" v-model:get-html="form.description" placeholder="请输入详情描述(HTML/文本)"></editor>
|
<template #default="scope">
|
||||||
</el-form-item>
|
<div class="sku-cell">
|
||||||
</el-col>
|
<el-input
|
||||||
|
v-model="scope.row.skuCode"
|
||||||
|
placeholder="请输入SKU编码"
|
||||||
|
size="small"
|
||||||
|
:class="{ 'is-error': !scope.row.skuCode && form.skuList.length > 0 }"
|
||||||
|
@blur="validateSkuField(scope.$index, 'skuCode')"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
|
||||||
<el-col :span="12" class="mb20">
|
<el-table-column label="SKU名称" min-width="220" align="center" show-overflow-tooltip>
|
||||||
<el-form-item label="部门ID" prop="deptId">
|
<template #header> <span class="required">*</span> SKU名称 </template>
|
||||||
<el-input v-model="form.deptId" placeholder="请输入部门ID"/>
|
<template #default="scope">
|
||||||
</el-form-item>
|
<div class="sku-cell">
|
||||||
</el-col>
|
<el-input
|
||||||
|
v-model="scope.row.skuName"
|
||||||
|
placeholder="请输入SKU名称"
|
||||||
|
size="small"
|
||||||
|
:class="{ 'is-error': !scope.row.skuName && form.skuList.length > 0 }"
|
||||||
|
@blur="validateSkuField(scope.$index, 'skuName')"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
|
||||||
</el-row>
|
<el-table-column label="售价" width="140" align="center">
|
||||||
</el-form>
|
<template #header> <span class="required">*</span> 售价(元) </template>
|
||||||
<template #footer>
|
<template #default="scope">
|
||||||
<span class="dialog-footer">
|
<div class="sku-cell">
|
||||||
<el-button @click="visible = false">取消</el-button>
|
<el-input-number
|
||||||
<el-button type="primary" @click="onSubmit" :disabled="loading">确认</el-button>
|
v-model="scope.row.price"
|
||||||
</span>
|
:precision="2"
|
||||||
</template>
|
:min="0"
|
||||||
</el-dialog>
|
size="small"
|
||||||
|
placeholder="0.00"
|
||||||
|
:class="{ 'is-error': (!scope.row.price || scope.row.price <= 0) && form.skuList.length > 0 }"
|
||||||
|
@blur="validateSkuField(scope.$index, 'price')"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
|
||||||
|
<el-table-column label="库存" width="150" align="center">
|
||||||
|
<template #header> <span class="required">*</span> 库存 </template>
|
||||||
|
<template #default="scope">
|
||||||
|
<div class="sku-cell">
|
||||||
|
<el-input-number
|
||||||
|
v-model="scope.row.stock"
|
||||||
|
:precision="2"
|
||||||
|
:min="0"
|
||||||
|
size="small"
|
||||||
|
placeholder="0.00"
|
||||||
|
:class="{ 'is-error': (scope.row.stock === undefined || scope.row.stock < 0) && form.skuList.length > 0 }"
|
||||||
|
@blur="validateSkuField(scope.$index, 'stock')"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
|
||||||
|
<el-table-column label="条码" min-width="150" align="center">
|
||||||
|
<template #default="scope">
|
||||||
|
<div class="sku-cell">
|
||||||
|
<el-input v-model="scope.row.barcode" placeholder="请输入条码" size="small" />
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
|
||||||
|
<el-table-column label="重量(克)" min-width="120" align="center">
|
||||||
|
<template #default="scope">
|
||||||
|
<div class="sku-cell">
|
||||||
|
<el-input-number v-model="scope.row.weightG" :min="0" size="small" placeholder="0" />
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
|
||||||
|
<el-table-column label="状态" min-width="100" align="center">
|
||||||
|
<template #default="scope">
|
||||||
|
<div class="sku-cell">
|
||||||
|
<el-radio-group v-model="scope.row.status" size="small">
|
||||||
|
<el-radio label="0">启用</el-radio>
|
||||||
|
<el-radio label="1">停用</el-radio>
|
||||||
|
</el-radio-group>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
|
||||||
|
<el-table-column label="操作" width="80" fixed="right" align="center">
|
||||||
|
<template #default="scope">
|
||||||
|
<el-button type="danger" size="small" @click="removeSku(scope.$index)" :disabled="form.skuList.length <= 1">
|
||||||
|
删除
|
||||||
|
</el-button>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
</el-table>
|
||||||
|
</div>
|
||||||
|
</el-tab-pane>
|
||||||
|
</el-tabs>
|
||||||
|
</el-form>
|
||||||
|
<template #footer>
|
||||||
|
<span class="dialog-footer">
|
||||||
|
<el-button @click="visible = false">取消</el-button>
|
||||||
|
<el-button type="primary" @click="onSubmit" :disabled="loading">确认</el-button>
|
||||||
|
</span>
|
||||||
|
</template>
|
||||||
|
</el-dialog>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts" name="MallProductDialog">
|
<script setup lang="ts" name="MallProductDialog">
|
||||||
import { useDict } from '/@/hooks/dict';
|
import { useDict } from "/@/hooks/dict"
|
||||||
import { useMessage } from "/@/hooks/message";
|
import { useMessage } from "/@/hooks/message"
|
||||||
import { getObj, addObj, putObj } from '/@/api/supermarket/mallProduct'
|
import { getObj, addObj, putObj } from "/@/api/supermarket/mallProduct"
|
||||||
import { rule } from '/@/utils/validate';
|
import { Plus } from "@element-plus/icons-vue"
|
||||||
const emit = defineEmits(['refresh']);
|
import { tree as fetchCategoryTree } from "/@/api/supermarket/mallCategory"
|
||||||
|
import { selectOption as fetchMerchantSelect } from "/@/api/supermarket/mallMerchant"
|
||||||
|
|
||||||
|
const emit = defineEmits(["refresh"])
|
||||||
|
|
||||||
// 定义变量内容
|
// 定义变量内容
|
||||||
const dataFormRef = ref();
|
const dataFormRef = ref()
|
||||||
const visible = ref(false)
|
const visible = ref(false)
|
||||||
const loading = ref(false)
|
const loading = ref(false)
|
||||||
|
const activeTab = ref("basic")
|
||||||
|
|
||||||
// 定义字典
|
// 定义字典
|
||||||
const { spu_status } = useDict('spu_status')
|
const { spu_status } = useDict("spu_status")
|
||||||
|
|
||||||
|
// 分类选项
|
||||||
|
const categoryOptions = ref<any[]>([])
|
||||||
|
|
||||||
|
// 商户选项
|
||||||
|
const merchantOptions = ref<any[]>([])
|
||||||
|
|
||||||
|
// 加载分类树
|
||||||
|
const loadCategoryTree = async (merchantId?: string) => {
|
||||||
|
if (!merchantId) {
|
||||||
|
categoryOptions.value = []
|
||||||
|
return
|
||||||
|
}
|
||||||
|
const res = await fetchCategoryTree({ merchantId })
|
||||||
|
categoryOptions.value = res.data || []
|
||||||
|
}
|
||||||
|
|
||||||
|
// 加载商户选项
|
||||||
|
const loadMerchantOptions = async () => {
|
||||||
|
const res = await fetchMerchantSelect()
|
||||||
|
merchantOptions.value = res.data || []
|
||||||
|
}
|
||||||
|
|
||||||
|
// 商户选择变化处理
|
||||||
|
const onMerchantChange = (merchantId: string) => {
|
||||||
|
// 清空分类选择
|
||||||
|
form.categoryId = ""
|
||||||
|
// 根据商户ID加载对应的分类树
|
||||||
|
loadCategoryTree(merchantId)
|
||||||
|
}
|
||||||
|
|
||||||
// 提交表单数据
|
// 提交表单数据
|
||||||
const form = reactive({
|
const form = reactive({
|
||||||
id:'',
|
id: "",
|
||||||
merchantId: '',
|
merchantId: "",
|
||||||
categoryId: '',
|
categoryId: "",
|
||||||
title: '',
|
title: "",
|
||||||
subTitle: '',
|
coverImage: "",
|
||||||
brand: '',
|
carouselImages: "",
|
||||||
coverImage: '',
|
priceType: 1, // 默认多SKU模式
|
||||||
carouselImages: '',
|
spuPrice: 0,
|
||||||
priceType: '',
|
originalPrice: 0,
|
||||||
spuPrice: '',
|
unit: "",
|
||||||
originalPrice: '',
|
status: "0", // 默认上架
|
||||||
totalStock: '',
|
saleStartTime: "",
|
||||||
unit: '',
|
saleEndTime: "",
|
||||||
status: '',
|
description: "",
|
||||||
saleStartTime: '',
|
skuList: [] as any[], // SKU列表
|
||||||
saleEndTime: '',
|
})
|
||||||
description: '',
|
|
||||||
deptId: '',
|
// SKU验证规则
|
||||||
});
|
const skuRules = {
|
||||||
|
skuCode: [{ required: true, message: "SKU编码不能为空", trigger: "blur" }],
|
||||||
|
skuName: [{ required: true, message: "SKU名称不能为空", trigger: "blur" }],
|
||||||
|
price: [{ required: true, message: "售价不能为空", trigger: "blur" }],
|
||||||
|
stock: [{ required: true, message: "库存不能为空", trigger: "blur" }],
|
||||||
|
}
|
||||||
|
|
||||||
// 定义校验规则
|
// 定义校验规则
|
||||||
const dataRules = ref({
|
const dataRules = ref({
|
||||||
merchantId: [{required: true, message: '商户ID不能为空', trigger: 'blur'}],
|
merchantId: [{ required: true, message: "商户不能为空", trigger: "change" }],
|
||||||
categoryId: [{required: true, message: '类目ID不能为空', trigger: 'blur'}],
|
categoryId: [{ required: true, message: "商品分类不能为空", trigger: "change" }],
|
||||||
title: [{required: true, message: '商品标题不能为空', trigger: 'blur'}],
|
title: [{ required: true, message: "商品标题不能为空", trigger: "blur" }],
|
||||||
coverImage: [{required: true, message: '主图不能为空', trigger: 'blur'}],
|
coverImage: [{ required: true, message: "主图不能为空", trigger: "blur" }],
|
||||||
status: [{required: true, message: '状态(1上架 0下架)不能为空', trigger: 'blur'}],
|
priceType: [{ required: true, message: "定价方式不能为空", trigger: "change" }],
|
||||||
|
spuPrice: [
|
||||||
|
{
|
||||||
|
validator: (rule: any, value: any, callback: any) => {
|
||||||
|
if (form.priceType === 2 && (!value || value <= 0)) {
|
||||||
|
callback(new Error("单价SPU模式下,SPU售价不能为空且必须大于0"))
|
||||||
|
} else {
|
||||||
|
callback()
|
||||||
|
}
|
||||||
|
},
|
||||||
|
trigger: "blur",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
status: [{ required: true, message: "状态不能为空", trigger: "change" }],
|
||||||
})
|
})
|
||||||
|
|
||||||
|
// 添加SKU
|
||||||
|
const addSku = () => {
|
||||||
|
form.skuList.push({
|
||||||
|
skuCode: "",
|
||||||
|
skuName: "",
|
||||||
|
price: 0,
|
||||||
|
stock: 0.0,
|
||||||
|
barcode: "",
|
||||||
|
weightG: 0,
|
||||||
|
status: "0",
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 删除SKU
|
||||||
|
const removeSku = (index: number) => {
|
||||||
|
if (form.skuList.length > 1) {
|
||||||
|
form.skuList.splice(index, 1)
|
||||||
|
} else {
|
||||||
|
useMessage().warning("至少需要保留一个SKU")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 定价方式改变
|
||||||
|
const onPriceTypeChange = (value: number) => {
|
||||||
|
if (value === 1) {
|
||||||
|
// 多SKU模式:确保至少有一个SKU
|
||||||
|
if (form.skuList.length === 0) {
|
||||||
|
addSku()
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// 单价SPU模式:清空SKU列表
|
||||||
|
form.skuList = []
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// SKU字段验证
|
||||||
|
const validateSkuField = (index: number, field: string) => {
|
||||||
|
const sku = form.skuList[index]
|
||||||
|
if (!sku) return
|
||||||
|
|
||||||
|
// 清除之前的错误状态
|
||||||
|
nextTick(() => {
|
||||||
|
// 这里可以添加具体的验证逻辑
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
// 打开弹窗
|
// 打开弹窗
|
||||||
const openDialog = (id: string) => {
|
const openDialog = (id: string) => {
|
||||||
visible.value = true
|
visible.value = true
|
||||||
form.id = ''
|
form.id = ""
|
||||||
|
activeTab.value = "basic"
|
||||||
|
|
||||||
// 重置表单数据
|
// 重置表单数据
|
||||||
nextTick(() => {
|
nextTick(() => {
|
||||||
dataFormRef.value?.resetFields();
|
dataFormRef.value?.resetFields()
|
||||||
});
|
// 重置表单对象
|
||||||
|
Object.assign(form, {
|
||||||
|
id: "",
|
||||||
|
merchantId: "",
|
||||||
|
categoryId: "",
|
||||||
|
title: "",
|
||||||
|
coverImage: "",
|
||||||
|
carouselImages: "",
|
||||||
|
priceType: 1,
|
||||||
|
spuPrice: 0,
|
||||||
|
originalPrice: 0,
|
||||||
|
unit: "",
|
||||||
|
status: "0",
|
||||||
|
saleStartTime: "",
|
||||||
|
saleEndTime: "",
|
||||||
|
description: "",
|
||||||
|
skuList: [],
|
||||||
|
})
|
||||||
|
// 默认添加一个SKU
|
||||||
|
addSku()
|
||||||
|
})
|
||||||
|
|
||||||
// 获取mallProduct信息
|
// 重新加载商户选项
|
||||||
if (id) {
|
loadMerchantOptions()
|
||||||
form.id = id
|
|
||||||
getmallProductData(id)
|
// 获取mallProduct信息
|
||||||
}
|
if (id) {
|
||||||
};
|
form.id = id
|
||||||
|
getmallProductData(id)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// 提交
|
// 提交
|
||||||
const onSubmit = async () => {
|
const onSubmit = async () => {
|
||||||
const valid = await dataFormRef.value.validate().catch(() => {});
|
// 验证基本信息
|
||||||
if (!valid) return false;
|
const valid = await dataFormRef.value.validate().catch(() => {})
|
||||||
|
if (!valid) return false
|
||||||
|
|
||||||
|
// 多SKU模式下的额外验证
|
||||||
|
if (form.priceType === 1) {
|
||||||
|
if (!form.skuList || form.skuList.length === 0) {
|
||||||
|
useMessage().error("多SKU模式下至少需要添加一个SKU")
|
||||||
|
activeTab.value = "sku"
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
// 验证SKU数据
|
||||||
|
for (let i = 0; i < form.skuList.length; i++) {
|
||||||
|
const sku = form.skuList[i]
|
||||||
|
if (!sku.skuCode || !sku.skuName || !sku.price || sku.stock === undefined) {
|
||||||
|
useMessage().error(`第${i + 1}个SKU信息不完整,请检查必填项`)
|
||||||
|
activeTab.value = "sku"
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
loading.value = true;
|
loading.value = true
|
||||||
form.id ? await putObj(form) : await addObj(form);
|
|
||||||
useMessage().success(form.id ? '修改成功' : '添加成功');
|
|
||||||
visible.value = false;
|
|
||||||
emit('refresh');
|
|
||||||
} catch (err: any) {
|
|
||||||
useMessage().error(err.msg);
|
|
||||||
} finally {
|
|
||||||
loading.value = false;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
|
// 准备提交数据
|
||||||
|
const submitData = { ...form }
|
||||||
|
|
||||||
|
// 处理分类ID:如果是数组,取最后一个值
|
||||||
|
if (Array.isArray(form.categoryId)) {
|
||||||
|
submitData.categoryId = form.categoryId.slice(-1)[0]
|
||||||
|
}
|
||||||
|
|
||||||
|
// 处理时间格式:转换为 LocalDateTime 格式 (yyyy-MM-dd HH:mm:ss)
|
||||||
|
if (form.saleStartTime) {
|
||||||
|
const date = new Date(form.saleStartTime)
|
||||||
|
submitData.saleStartTime = date.toISOString().slice(0, 19).replace("T", " ")
|
||||||
|
}
|
||||||
|
if (form.saleEndTime) {
|
||||||
|
const date = new Date(form.saleEndTime)
|
||||||
|
submitData.saleEndTime = date.toISOString().slice(0, 19).replace("T", " ")
|
||||||
|
}
|
||||||
|
|
||||||
|
// 如果是单价SPU模式,清空SKU列表
|
||||||
|
if (form.priceType === 2) {
|
||||||
|
submitData.skuList = []
|
||||||
|
}
|
||||||
|
|
||||||
|
// 价格转换:元转分
|
||||||
|
if (submitData.spuPrice) {
|
||||||
|
submitData.spuPrice = Math.round(submitData.spuPrice * 100)
|
||||||
|
}
|
||||||
|
if (submitData.originalPrice) {
|
||||||
|
submitData.originalPrice = Math.round(submitData.originalPrice * 100)
|
||||||
|
}
|
||||||
|
if (submitData.skuList && submitData.skuList.length > 0) {
|
||||||
|
submitData.skuList = submitData.skuList.map((sku: any) => ({
|
||||||
|
...sku,
|
||||||
|
price: sku.price ? Math.round(sku.price * 100) : 0,
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
|
||||||
|
form.id ? await putObj(submitData) : await addObj(submitData)
|
||||||
|
useMessage().success(form.id ? "修改成功" : "添加成功")
|
||||||
|
visible.value = false
|
||||||
|
emit("refresh")
|
||||||
|
} catch (err: any) {
|
||||||
|
useMessage().error(err.msg)
|
||||||
|
} finally {
|
||||||
|
loading.value = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// 初始化表单数据
|
// 初始化表单数据
|
||||||
const getmallProductData = (id: string) => {
|
const getmallProductData = async (id: string) => {
|
||||||
// 获取数据
|
// 获取数据
|
||||||
loading.value = true
|
loading.value = true
|
||||||
getObj(id).then((res: any) => {
|
try {
|
||||||
Object.assign(form, res.data)
|
const res = await getObj(id)
|
||||||
}).finally(() => {
|
Object.assign(form, res.data)
|
||||||
loading.value = false
|
|
||||||
})
|
// 先根据商户ID加载分类树
|
||||||
};
|
if (form.merchantId) {
|
||||||
|
await loadCategoryTree(form.merchantId)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 价格转换:分转元
|
||||||
|
if (form.spuPrice) {
|
||||||
|
form.spuPrice = form.spuPrice / 100
|
||||||
|
}
|
||||||
|
if (form.originalPrice) {
|
||||||
|
form.originalPrice = form.originalPrice / 100
|
||||||
|
}
|
||||||
|
if (form.skuList && form.skuList.length > 0) {
|
||||||
|
form.skuList = form.skuList.map((sku: any) => ({
|
||||||
|
...sku,
|
||||||
|
price: sku.price ? sku.price / 100 : 0,
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
|
||||||
|
// 处理分类ID回显为数组
|
||||||
|
if (res.data.categoryId && categoryOptions.value.length) {
|
||||||
|
form.categoryId = findCategoryPath(categoryOptions.value, res.data.categoryId) as any
|
||||||
|
}
|
||||||
|
|
||||||
|
// 如果没有SKU数据,根据定价方式初始化
|
||||||
|
if (!form.skuList || form.skuList.length === 0) {
|
||||||
|
if (form.priceType === 1) {
|
||||||
|
addSku()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
loading.value = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 工具函数:根据分类id查找路径
|
||||||
|
function findCategoryPath(options: any[], targetId: any, path: any[] = []): any[] {
|
||||||
|
for (const item of options) {
|
||||||
|
const newPath = path.concat(item.id)
|
||||||
|
if (item.id === targetId) return newPath
|
||||||
|
if (item.children) {
|
||||||
|
const childPath = findCategoryPath(item.children, targetId, newPath)
|
||||||
|
if (childPath.length) return childPath
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return []
|
||||||
|
}
|
||||||
|
|
||||||
|
// 组件挂载时加载商户选项
|
||||||
|
onMounted(() => {
|
||||||
|
loadMerchantOptions()
|
||||||
|
})
|
||||||
|
|
||||||
// 暴露变量
|
// 暴露变量
|
||||||
defineExpose({
|
defineExpose({
|
||||||
openDialog
|
openDialog,
|
||||||
});
|
})
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
<style scoped lang="scss">
|
||||||
|
.sku-header {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 20px;
|
||||||
|
margin-bottom: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.sku-tip {
|
||||||
|
color: #909399;
|
||||||
|
font-size: 14px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.required {
|
||||||
|
color: #f56c6c;
|
||||||
|
margin-right: 4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
// SKU表格容器样式
|
||||||
|
.sku-table-container {
|
||||||
|
margin-top: 20px;
|
||||||
|
background: #fff;
|
||||||
|
border-radius: 6px;
|
||||||
|
overflow: hidden;
|
||||||
|
box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1);
|
||||||
|
}
|
||||||
|
|
||||||
|
// SKU表格样式
|
||||||
|
.sku-table {
|
||||||
|
width: 100%;
|
||||||
|
|
||||||
|
:deep(.el-table__header) {
|
||||||
|
background: #f5f7fa;
|
||||||
|
|
||||||
|
th {
|
||||||
|
background: #f5f7fa !important;
|
||||||
|
border-bottom: 1px solid #e4e7ed;
|
||||||
|
font-weight: 600;
|
||||||
|
color: #303133;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
:deep(.el-table__body) {
|
||||||
|
tr {
|
||||||
|
&:hover {
|
||||||
|
background: #f5f7fa;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
td {
|
||||||
|
padding: 8px 0;
|
||||||
|
border-bottom: 1px solid #f0f0f0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 确保表格占满容器宽度
|
||||||
|
:deep(.el-table__header-wrapper),
|
||||||
|
:deep(.el-table__body-wrapper) {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// SKU单元格样式
|
||||||
|
.sku-cell {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
min-height: 32px;
|
||||||
|
padding: 4px 8px;
|
||||||
|
|
||||||
|
// 输入框样式
|
||||||
|
:deep(.el-input) {
|
||||||
|
.el-input__wrapper {
|
||||||
|
border-radius: 4px;
|
||||||
|
box-shadow: 0 0 0 1px #dcdfe6 inset;
|
||||||
|
transition: all 0.3s;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
box-shadow: 0 0 0 1px #c0c4cc inset;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.is-focus {
|
||||||
|
box-shadow: 0 0 0 1px #409eff inset;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.is-error {
|
||||||
|
box-shadow: 0 0 0 1px #f56c6c inset;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.el-input__inner {
|
||||||
|
text-align: center;
|
||||||
|
font-size: 13px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 数字输入框样式
|
||||||
|
:deep(.el-input-number) {
|
||||||
|
width: 100%;
|
||||||
|
|
||||||
|
.el-input__wrapper {
|
||||||
|
border-radius: 4px;
|
||||||
|
box-shadow: 0 0 0 1px #dcdfe6 inset;
|
||||||
|
transition: all 0.3s;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
box-shadow: 0 0 0 1px #c0c4cc inset;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.is-focus {
|
||||||
|
box-shadow: 0 0 0 1px #409eff inset;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.is-error {
|
||||||
|
box-shadow: 0 0 0 1px #f56c6c inset;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.el-input__inner {
|
||||||
|
text-align: center;
|
||||||
|
font-size: 13px;
|
||||||
|
padding: 0 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.el-input-number__decrease,
|
||||||
|
.el-input-number__increase {
|
||||||
|
width: 20px;
|
||||||
|
height: 20px;
|
||||||
|
line-height: 20px;
|
||||||
|
font-size: 10px;
|
||||||
|
top: 50%;
|
||||||
|
transform: translateY(-50%);
|
||||||
|
}
|
||||||
|
|
||||||
|
.el-input-number__decrease {
|
||||||
|
left: 2px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.el-input-number__increase {
|
||||||
|
right: 2px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 单选框组样式
|
||||||
|
:deep(.el-radio-group) {
|
||||||
|
.el-radio {
|
||||||
|
margin-right: 8px;
|
||||||
|
|
||||||
|
.el-radio__label {
|
||||||
|
font-size: 13px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 按钮样式
|
||||||
|
:deep(.el-button) {
|
||||||
|
border-radius: 4px;
|
||||||
|
font-size: 12px;
|
||||||
|
padding: 4px 8px;
|
||||||
|
height: 24px;
|
||||||
|
line-height: 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 错误状态样式
|
||||||
|
.is-error {
|
||||||
|
:deep(.el-input__wrapper) {
|
||||||
|
box-shadow: 0 0 0 1px #f56c6c inset !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
:deep(.el-input-number__wrapper) {
|
||||||
|
box-shadow: 0 0 0 1px #f56c6c inset !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 表格响应式处理
|
||||||
|
@media (max-width: 1200px) {
|
||||||
|
.sku-table-container {
|
||||||
|
overflow-x: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.sku-table {
|
||||||
|
min-width: 800px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 移除背景水印影响
|
||||||
|
:deep(.el-dialog) {
|
||||||
|
background: #fff;
|
||||||
|
position: relative;
|
||||||
|
z-index: 2000;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 价格提示样式
|
||||||
|
.price-tip {
|
||||||
|
font-size: 12px;
|
||||||
|
color: #909399;
|
||||||
|
margin-left: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
:deep(.el-dialog__body) {
|
||||||
|
background: #fff;
|
||||||
|
position: relative;
|
||||||
|
z-index: 2001;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 优化表单项间距
|
||||||
|
:deep(.el-form-item) {
|
||||||
|
margin-bottom: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
:deep(.el-form-item__error) {
|
||||||
|
position: absolute;
|
||||||
|
top: 100%;
|
||||||
|
left: 0;
|
||||||
|
z-index: 10;
|
||||||
|
background: #fff;
|
||||||
|
padding: 2px 8px;
|
||||||
|
border: 1px solid #f56c6c;
|
||||||
|
border-radius: 4px;
|
||||||
|
font-size: 12px;
|
||||||
|
white-space: nowrap;
|
||||||
|
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@@ -1,94 +1,247 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="layout-padding">
|
<div class="layout-padding">
|
||||||
<div class="layout-padding-auto layout-padding-view">
|
<div class="layout-padding-auto layout-padding-view">
|
||||||
<el-row v-show="showSearch">
|
<el-row v-show="showSearch">
|
||||||
<el-form :model="state.queryForm" ref="queryRef" :inline="true" @keyup.enter="getDataList">
|
<el-form :model="state.queryForm" ref="queryRef" :inline="true" @keyup.enter="getDataList">
|
||||||
<el-form-item label="类目ID" prop="categoryId" >
|
<el-form-item label="类目ID" prop="categoryId">
|
||||||
<el-input placeholder="请输入类目ID" v-model="state.queryForm.categoryId" />
|
<el-input placeholder="请输入类目ID" v-model="state.queryForm.categoryId" />
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item label="商品标题" prop="title" >
|
<el-form-item label="商品标题" prop="title">
|
||||||
<el-input placeholder="请输入商品标题" v-model="state.queryForm.title" />
|
<el-input placeholder="请输入商品标题" v-model="state.queryForm.title" />
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item>
|
<el-form-item>
|
||||||
<el-button icon="search" type="primary" @click="getDataList">
|
<el-button icon="search" type="primary" @click="getDataList"> 查询 </el-button>
|
||||||
查询
|
<el-button icon="Refresh" @click="resetQuery">重置</el-button>
|
||||||
</el-button>
|
</el-form-item>
|
||||||
<el-button icon="Refresh" @click="resetQuery">重置</el-button>
|
</el-form>
|
||||||
</el-form-item>
|
</el-row>
|
||||||
</el-form>
|
<el-row>
|
||||||
</el-row>
|
<div class="mb8" style="width: 100%">
|
||||||
<el-row>
|
<el-button
|
||||||
<div class="mb8" style="width: 100%">
|
icon="folder-add"
|
||||||
<el-button icon="folder-add" type="primary" class="ml10" @click="formDialogRef.openDialog()"
|
type="primary"
|
||||||
v-auth="'supermarket_mallProduct_add'">
|
class="ml10"
|
||||||
新 增
|
@click="formDialogRef.openDialog()"
|
||||||
</el-button>
|
v-auth="'supermarket_mallProduct_add'"
|
||||||
<el-button plain :disabled="multiple" icon="Delete" type="primary"
|
>
|
||||||
v-auth="'supermarket_mallProduct_del'" @click="handleDelete(selectObjs)">
|
新 增
|
||||||
删除
|
</el-button>
|
||||||
</el-button>
|
<el-button
|
||||||
<right-toolbar v-model:showSearch="showSearch" :export="'supermarket_mallProduct_export'"
|
plain
|
||||||
@exportExcel="exportExcel" class="ml10 mr20" style="float: right;"
|
:disabled="multiple"
|
||||||
@queryTable="getDataList"></right-toolbar>
|
icon="Delete"
|
||||||
</div>
|
type="primary"
|
||||||
</el-row>
|
v-auth="'supermarket_mallProduct_del'"
|
||||||
<el-table :data="state.dataList" v-loading="state.loading" border
|
@click="handleDelete(selectObjs)"
|
||||||
:cell-style="tableStyle.cellStyle" :header-cell-style="tableStyle.headerCellStyle"
|
>
|
||||||
|
删 除
|
||||||
|
</el-button>
|
||||||
|
<right-toolbar
|
||||||
|
v-model:showSearch="showSearch"
|
||||||
|
:export="'supermarket_mallProduct_export'"
|
||||||
|
@exportExcel="exportExcel"
|
||||||
|
class="ml10 mr20"
|
||||||
|
style="float: right"
|
||||||
|
@queryTable="getDataList"
|
||||||
|
></right-toolbar>
|
||||||
|
</div>
|
||||||
|
</el-row>
|
||||||
|
<el-table
|
||||||
|
:data="state.dataList"
|
||||||
|
v-loading="state.loading"
|
||||||
|
border
|
||||||
|
:cell-style="tableStyle.cellStyle"
|
||||||
|
:header-cell-style="tableStyle.headerCellStyle"
|
||||||
@selection-change="selectionChangHandle"
|
@selection-change="selectionChangHandle"
|
||||||
@sort-change="sortChangeHandle">
|
@sort-change="sortChangeHandle"
|
||||||
<el-table-column type="selection" width="40" align="center" />
|
>
|
||||||
<el-table-column type="index" label="#" width="40" />
|
<el-table-column type="selection" width="40" align="center" />
|
||||||
<el-table-column prop="merchantId" label="商户ID" show-overflow-tooltip/>
|
<el-table-column type="index" label="#" width="40" />
|
||||||
<el-table-column prop="categoryId" label="类目ID" show-overflow-tooltip/>
|
|
||||||
<el-table-column prop="title" label="商品标题" show-overflow-tooltip/>
|
|
||||||
<el-table-column prop="subTitle" label="副标题" show-overflow-tooltip/>
|
|
||||||
<el-table-column prop="brand" label="品牌" show-overflow-tooltip/>
|
|
||||||
<el-table-column prop="coverImage" label="主图" show-overflow-tooltip/>
|
|
||||||
<el-table-column prop="carouselImages" label="SPU轮播图URL(逗号分隔,按顺序)" show-overflow-tooltip/>
|
|
||||||
<el-table-column prop="priceType" label="定价方式(1多SKU 2单价SPU)" show-overflow-tooltip/>
|
|
||||||
<el-table-column prop="spuPrice" label="SPU售价(当price_type=2有效)" show-overflow-tooltip/>
|
|
||||||
<el-table-column prop="originalPrice" label="划线价" show-overflow-tooltip/>
|
|
||||||
<el-table-column prop="totalStock" label="总库存(冗余)" show-overflow-tooltip/>
|
|
||||||
<el-table-column prop="unit" label="计量单位" show-overflow-tooltip/>
|
|
||||||
<el-table-column prop="status" label="状态(1上架 0下架)" show-overflow-tooltip>
|
|
||||||
<template #default="scope">
|
|
||||||
<dict-tag :options="spu_status" :value="scope.row.status"></dict-tag>
|
|
||||||
</template>
|
|
||||||
</el-table-column>
|
|
||||||
<el-table-column prop="saleStartTime" label="开售时间" show-overflow-tooltip/>
|
|
||||||
<el-table-column prop="saleEndTime" label="停售时间" show-overflow-tooltip/>
|
|
||||||
<el-table-column prop="description" label="详情描述(HTML/文本)" show-overflow-tooltip/>
|
|
||||||
<el-table-column prop="deptId" label="部门ID" show-overflow-tooltip/>
|
|
||||||
<el-table-column label="操作" width="150">
|
|
||||||
<template #default="scope">
|
|
||||||
<el-button icon="edit-pen" text type="primary" v-auth="'supermarket_mallProduct_edit'"
|
|
||||||
@click="formDialogRef.openDialog(scope.row.id)">编辑</el-button>
|
|
||||||
<el-button icon="delete" text type="primary" v-auth="'supermarket_mallProduct_del'" @click="handleDelete([scope.row.id])">删除</el-button>
|
|
||||||
</template>
|
|
||||||
</el-table-column>
|
|
||||||
</el-table>
|
|
||||||
<pagination @size-change="sizeChangeHandle" @current-change="currentChangeHandle" v-bind="state.pagination" />
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- 编辑、新增 -->
|
<el-table-column prop="title" label="商品标题" width="200" show-overflow-tooltip />
|
||||||
<form-dialog ref="formDialogRef" @refresh="getDataList(false)" />
|
|
||||||
|
|
||||||
</div>
|
<el-table-column prop="merchantId" label="商户" width="150" show-overflow-tooltip>
|
||||||
|
<template #default="scope">
|
||||||
|
{{ getMerchantName(scope.row.merchantId) }}
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
|
||||||
|
<el-table-column prop="categoryId" label="商品分类" width="150" show-overflow-tooltip>
|
||||||
|
<template #default="scope">
|
||||||
|
{{ getCategoryName(scope.row.categoryId) }}
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
|
||||||
|
<el-table-column prop="priceType" label="定价方式" width="120" align="center">
|
||||||
|
<template #default="scope">
|
||||||
|
<el-tag :type="scope.row.priceType === 1 ? 'primary' : 'success'">
|
||||||
|
{{ scope.row.priceType === 1 ? "多SKU" : "单价SPU" }}
|
||||||
|
</el-tag>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
|
||||||
|
<el-table-column label="价格信息" width="200">
|
||||||
|
<template #default="scope">
|
||||||
|
<div v-if="scope.row.priceType === 1">
|
||||||
|
<div v-if="scope.row.skuList && scope.row.skuList.length > 0">
|
||||||
|
<div class="price-range">
|
||||||
|
<span class="min-price">¥{{ getMinPrice(scope.row.skuList) }}</span>
|
||||||
|
<span v-if="getMinPrice(scope.row.skuList) !== getMaxPrice(scope.row.skuList)">
|
||||||
|
- ¥{{ getMaxPrice(scope.row.skuList) }}</span
|
||||||
|
>
|
||||||
|
</div>
|
||||||
|
<div class="sku-count">{{ scope.row.skuList.length }}个SKU</div>
|
||||||
|
</div>
|
||||||
|
<div v-else class="no-sku">暂无SKU</div>
|
||||||
|
</div>
|
||||||
|
<div v-else>
|
||||||
|
<div class="spu-price">¥{{ ((scope.row.spuPrice || 0) / 100).toFixed(2) }}</div>
|
||||||
|
<div v-if="scope.row.originalPrice" class="original-price">¥{{ ((scope.row.originalPrice || 0) / 100).toFixed(2) }}</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
|
||||||
|
<el-table-column label="库存信息" width="120">
|
||||||
|
<template #default="scope">
|
||||||
|
<div v-if="scope.row.priceType === 1">
|
||||||
|
<div v-if="scope.row.skuList && scope.row.skuList.length > 0">
|
||||||
|
<div class="total-stock">{{ getTotalStock(scope.row.skuList) }}</div>
|
||||||
|
<div class="sku-count">{{ scope.row.skuList.length }}个SKU</div>
|
||||||
|
</div>
|
||||||
|
<div v-else class="no-stock">0</div>
|
||||||
|
</div>
|
||||||
|
<div v-else>
|
||||||
|
<div class="spu-stock">{{ scope.row.totalStock || 0 }}</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
|
||||||
|
<el-table-column prop="unit" label="单位" width="80" align="center" />
|
||||||
|
|
||||||
|
<el-table-column prop="status" label="状态" width="100" align="center">
|
||||||
|
<template #default="scope">
|
||||||
|
<el-tag :type="scope.row.status === '0' ? 'success' : 'danger'">
|
||||||
|
{{ scope.row.status === "0" ? "上架" : "下架" }}
|
||||||
|
</el-tag>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
|
||||||
|
<el-table-column prop="saleStartTime" label="开售时间" width="160" show-overflow-tooltip />
|
||||||
|
|
||||||
|
<el-table-column prop="saleEndTime" label="停售时间" width="160" show-overflow-tooltip />
|
||||||
|
|
||||||
|
<el-table-column label="SKU详情" width="120" align="center">
|
||||||
|
<template #default="scope">
|
||||||
|
<el-button
|
||||||
|
v-if="scope.row.priceType === 1 && scope.row.skuList && scope.row.skuList.length > 0"
|
||||||
|
type="primary"
|
||||||
|
size="small"
|
||||||
|
@click="showSkuDetail(scope.row)"
|
||||||
|
>
|
||||||
|
查看SKU
|
||||||
|
</el-button>
|
||||||
|
<span v-else class="no-sku-detail">-</span>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
|
||||||
|
<el-table-column label="操作" width="180" fixed="right">
|
||||||
|
<template #default="scope">
|
||||||
|
<el-button
|
||||||
|
icon="edit-pen"
|
||||||
|
text
|
||||||
|
type="primary"
|
||||||
|
v-auth="'supermarket_mallProduct_edit'"
|
||||||
|
@click="formDialogRef.openDialog(scope.row.id)"
|
||||||
|
>编辑</el-button
|
||||||
|
>
|
||||||
|
<el-button icon="delete" text type="primary" v-auth="'supermarket_mallProduct_del'" @click="handleDelete([scope.row.id])"
|
||||||
|
>删除</el-button
|
||||||
|
>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
</el-table>
|
||||||
|
<pagination @size-change="sizeChangeHandle" @current-change="currentChangeHandle" v-bind="state.pagination" />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 编辑、新增 -->
|
||||||
|
<form-dialog ref="formDialogRef" @refresh="getDataList(false)" />
|
||||||
|
|
||||||
|
<!-- SKU详情弹窗 -->
|
||||||
|
<el-dialog v-model="skuDetailVisible" title="SKU详情" width="80%" :close-on-click-modal="false">
|
||||||
|
<div v-if="currentProduct">
|
||||||
|
<div class="product-info">
|
||||||
|
<h3>{{ currentProduct.title }}</h3>
|
||||||
|
<p class="product-desc">{{ currentProduct.subTitle }}</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<el-table :data="currentProduct.skuList" border style="margin-top: 20px">
|
||||||
|
<el-table-column type="index" label="#" width="60" align="center" />
|
||||||
|
<el-table-column prop="skuCode" label="SKU编码" width="150" />
|
||||||
|
<el-table-column prop="skuName" label="SKU名称" width="200" />
|
||||||
|
<el-table-column prop="price" label="售价" width="120" align="right">
|
||||||
|
<template #default="scope">
|
||||||
|
<span class="price">¥{{ ((scope.row.price || 0) / 100).toFixed(2) }}</span>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
<el-table-column prop="stock" label="库存" width="100" align="center" />
|
||||||
|
<el-table-column prop="barcode" label="条码" width="150" />
|
||||||
|
<el-table-column prop="weightG" label="重量(克)" width="120" align="center" />
|
||||||
|
<el-table-column prop="status" label="状态" width="100" align="center">
|
||||||
|
<template #default="scope">
|
||||||
|
<el-tag :type="scope.row.status === '0' ? 'success' : 'danger'">
|
||||||
|
{{ scope.row.status === "0" ? "启用" : "停用" }}
|
||||||
|
</el-tag>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
</el-table>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<template #footer>
|
||||||
|
<span class="dialog-footer">
|
||||||
|
<el-button @click="skuDetailVisible = false">关闭</el-button>
|
||||||
|
</span>
|
||||||
|
</template>
|
||||||
|
</el-dialog>
|
||||||
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts" name="systemMallProduct">
|
<script setup lang="ts" name="systemMallProduct">
|
||||||
import { BasicTableProps, useTable } from "/@/hooks/table";
|
import { BasicTableProps, useTable } from "/@/hooks/table"
|
||||||
import { fetchList, delObjs } from "/@/api/supermarket/mallProduct";
|
import { fetchList, delObjs } from "/@/api/supermarket/mallProduct"
|
||||||
import { useMessage, useMessageBox } from "/@/hooks/message";
|
import { useMessage, useMessageBox } from "/@/hooks/message"
|
||||||
import { useDict } from '/@/hooks/dict';
|
import { useDict } from "/@/hooks/dict"
|
||||||
|
import { tree as fetchCategoryTree } from "/@/api/supermarket/mallCategory"
|
||||||
|
import { selectOption as fetchMerchantSelect } from "/@/api/supermarket/mallMerchant"
|
||||||
|
|
||||||
// 引入组件
|
// 引入组件
|
||||||
const FormDialog = defineAsyncComponent(() => import('./form.vue'));
|
const FormDialog = defineAsyncComponent(() => import("./form.vue"))
|
||||||
// 定义查询字典
|
|
||||||
|
// 定义查询字典
|
||||||
|
const { spu_status } = useDict("spu_status")
|
||||||
|
|
||||||
|
// 分类选项
|
||||||
|
const categoryOptions = ref<any[]>([])
|
||||||
|
|
||||||
|
// 商户选项
|
||||||
|
const merchantOptions = ref<any[]>([])
|
||||||
|
|
||||||
|
// 加载分类树
|
||||||
|
const loadCategoryTree = async () => {
|
||||||
|
const res = await fetchCategoryTree()
|
||||||
|
categoryOptions.value = res.data || []
|
||||||
|
}
|
||||||
|
|
||||||
|
// 加载商户选项
|
||||||
|
const loadMerchantOptions = async () => {
|
||||||
|
const res = await fetchMerchantSelect()
|
||||||
|
merchantOptions.value = res.data || []
|
||||||
|
}
|
||||||
|
|
||||||
const { spu_status } = useDict('spu_status')
|
|
||||||
// 定义变量内容
|
// 定义变量内容
|
||||||
const formDialogRef = ref()
|
const formDialogRef = ref()
|
||||||
|
const skuDetailVisible = ref(false)
|
||||||
|
const currentProduct = ref(null)
|
||||||
|
|
||||||
// 搜索变量
|
// 搜索变量
|
||||||
const queryRef = ref()
|
const queryRef = ref()
|
||||||
const showSearch = ref(true)
|
const showSearch = ref(true)
|
||||||
@@ -97,54 +250,169 @@ const selectObjs = ref([]) as any
|
|||||||
const multiple = ref(true)
|
const multiple = ref(true)
|
||||||
|
|
||||||
const state: BasicTableProps = reactive<BasicTableProps>({
|
const state: BasicTableProps = reactive<BasicTableProps>({
|
||||||
queryForm: {},
|
queryForm: {},
|
||||||
pageList: fetchList
|
pageList: fetchList,
|
||||||
})
|
})
|
||||||
|
|
||||||
// table hook
|
// table hook
|
||||||
const {
|
const { getDataList, currentChangeHandle, sizeChangeHandle, sortChangeHandle, downBlobFile, tableStyle } = useTable(state)
|
||||||
getDataList,
|
|
||||||
currentChangeHandle,
|
// 获取SKU最低价格
|
||||||
sizeChangeHandle,
|
const getMinPrice = (skuList: any[]) => {
|
||||||
sortChangeHandle,
|
if (!skuList || skuList.length === 0) return 0
|
||||||
downBlobFile,
|
return Math.min(...skuList.map((sku) => (sku.price || 0) / 100)).toFixed(2)
|
||||||
tableStyle
|
}
|
||||||
} = useTable(state)
|
|
||||||
|
// 获取SKU最高价格
|
||||||
|
const getMaxPrice = (skuList: any[]) => {
|
||||||
|
if (!skuList || skuList.length === 0) return 0
|
||||||
|
return Math.max(...skuList.map((sku) => (sku.price || 0) / 100)).toFixed(2)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取SKU总库存
|
||||||
|
const getTotalStock = (skuList: any[]) => {
|
||||||
|
if (!skuList || skuList.length === 0) return 0
|
||||||
|
return skuList.reduce((total, sku) => total + (sku.stock || 0), 0)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 根据分类ID查找分类名称
|
||||||
|
const getCategoryName = (categoryId: any) => {
|
||||||
|
if (!categoryId || !categoryOptions.value.length) return "-"
|
||||||
|
|
||||||
|
const findCategory = (options: any[], targetId: any): any => {
|
||||||
|
for (const item of options) {
|
||||||
|
if (item.id === targetId) return item
|
||||||
|
if (item.children) {
|
||||||
|
const found = findCategory(item.children, targetId)
|
||||||
|
if (found) return found
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
const category = findCategory(categoryOptions.value, categoryId)
|
||||||
|
return category ? category.name : "-"
|
||||||
|
}
|
||||||
|
|
||||||
|
// 根据商户ID查找商户名称
|
||||||
|
const getMerchantName = (merchantId: any) => {
|
||||||
|
if (!merchantId || !merchantOptions.value.length) return "-"
|
||||||
|
const merchant = merchantOptions.value.find((item) => item.value === merchantId)
|
||||||
|
return merchant ? merchant.label : "-"
|
||||||
|
}
|
||||||
|
|
||||||
|
// 显示SKU详情
|
||||||
|
const showSkuDetail = (product: any) => {
|
||||||
|
currentProduct.value = product
|
||||||
|
skuDetailVisible.value = true
|
||||||
|
}
|
||||||
|
|
||||||
// 清空搜索条件
|
// 清空搜索条件
|
||||||
const resetQuery = () => {
|
const resetQuery = () => {
|
||||||
// 清空搜索条件
|
// 清空搜索条件
|
||||||
queryRef.value?.resetFields()
|
queryRef.value?.resetFields()
|
||||||
// 清空多选
|
// 清空多选
|
||||||
selectObjs.value = []
|
selectObjs.value = []
|
||||||
getDataList()
|
getDataList()
|
||||||
}
|
}
|
||||||
|
|
||||||
// 导出excel
|
// 导出excel
|
||||||
const exportExcel = () => {
|
const exportExcel = () => {
|
||||||
downBlobFile('/supermarket/mallProduct/export', Object.assign(state.queryForm, { ids: selectObjs }), 'mallProduct.xlsx')
|
downBlobFile("/supermarket/mallProduct/export", Object.assign(state.queryForm, { ids: selectObjs }), "mallProduct.xlsx")
|
||||||
}
|
}
|
||||||
|
|
||||||
// 多选事件
|
// 多选事件
|
||||||
const selectionChangHandle = (objs: { id: string }[]) => {
|
const selectionChangHandle = (objs: { id: string }[]) => {
|
||||||
selectObjs.value = objs.map(({ id }) => id);
|
selectObjs.value = objs.map(({ id }) => id)
|
||||||
multiple.value = !objs.length;
|
multiple.value = !objs.length
|
||||||
};
|
}
|
||||||
|
|
||||||
// 删除操作
|
// 删除操作
|
||||||
const handleDelete = async (ids: string[]) => {
|
const handleDelete = async (ids: string[]) => {
|
||||||
try {
|
try {
|
||||||
await useMessageBox().confirm('此操作将永久删除');
|
await useMessageBox().confirm("此操作将永久删除")
|
||||||
} catch {
|
} catch {
|
||||||
return;
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
await delObjs(ids);
|
await delObjs(ids)
|
||||||
getDataList();
|
getDataList()
|
||||||
useMessage().success('删除成功');
|
useMessage().success("删除成功")
|
||||||
} catch (err: any) {
|
} catch (err: any) {
|
||||||
useMessage().error(err.msg);
|
useMessage().error(err.msg)
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
</script>
|
|
||||||
|
// 组件挂载时加载分类树和商户选项
|
||||||
|
onMounted(() => {
|
||||||
|
loadCategoryTree()
|
||||||
|
loadMerchantOptions()
|
||||||
|
})
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped lang="scss">
|
||||||
|
.price-range {
|
||||||
|
font-weight: bold;
|
||||||
|
color: #e6a23c;
|
||||||
|
}
|
||||||
|
|
||||||
|
.min-price {
|
||||||
|
font-size: 16px;
|
||||||
|
font-weight: bold;
|
||||||
|
color: #f56c6c;
|
||||||
|
}
|
||||||
|
|
||||||
|
.spu-price {
|
||||||
|
font-size: 16px;
|
||||||
|
font-weight: bold;
|
||||||
|
color: #f56c6c;
|
||||||
|
}
|
||||||
|
|
||||||
|
.original-price {
|
||||||
|
font-size: 12px;
|
||||||
|
color: #909399;
|
||||||
|
text-decoration: line-through;
|
||||||
|
}
|
||||||
|
|
||||||
|
.total-stock,
|
||||||
|
.spu-stock {
|
||||||
|
font-weight: bold;
|
||||||
|
color: #67c23a;
|
||||||
|
}
|
||||||
|
|
||||||
|
.sku-count {
|
||||||
|
font-size: 12px;
|
||||||
|
color: #909399;
|
||||||
|
}
|
||||||
|
|
||||||
|
.no-sku,
|
||||||
|
.no-stock,
|
||||||
|
.no-sku-detail {
|
||||||
|
color: #c0c4cc;
|
||||||
|
font-style: italic;
|
||||||
|
}
|
||||||
|
|
||||||
|
.product-info {
|
||||||
|
margin-bottom: 20px;
|
||||||
|
padding: 15px;
|
||||||
|
background: #f5f7fa;
|
||||||
|
border-radius: 4px;
|
||||||
|
|
||||||
|
h3 {
|
||||||
|
margin: 0 0 8px 0;
|
||||||
|
color: #303133;
|
||||||
|
}
|
||||||
|
|
||||||
|
.product-desc {
|
||||||
|
margin: 0;
|
||||||
|
color: #606266;
|
||||||
|
font-size: 14px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.price {
|
||||||
|
color: #f56c6c;
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@@ -1,160 +1,153 @@
|
|||||||
<template>
|
<template>
|
||||||
<el-dialog :title="form.id ? '编辑' : '新增'" v-model="visible"
|
<el-dialog :title="form.id ? '编辑' : '新增'" v-model="visible" :close-on-click-modal="false" draggable>
|
||||||
:close-on-click-modal="false" draggable>
|
<el-form ref="dataFormRef" :model="form" :rules="dataRules" formDialogRef label-width="90px" v-loading="loading">
|
||||||
<el-form ref="dataFormRef" :model="form" :rules="dataRules" formDialogRef label-width="90px" v-loading="loading">
|
<el-row :gutter="24">
|
||||||
<el-row :gutter="24">
|
<el-col :span="12" class="mb20">
|
||||||
<el-col :span="12" class="mb20">
|
<el-form-item label="父级分类" prop="parentId">
|
||||||
<el-form-item label="父级分类" prop="parentId">
|
<el-select v-model="form.parentId" clearable placeholder="请选择父级分类">
|
||||||
<el-select v-model="form.parentId" clearable placeholder="请选择父级分类">
|
<el-option v-for="item in categoryOptions" :key="item.id" :label="item.name" :value="item.id" />
|
||||||
<el-option
|
</el-select>
|
||||||
v-for="item in categoryOptions"
|
</el-form-item>
|
||||||
:key="item.id"
|
</el-col>
|
||||||
:label="item.name"
|
|
||||||
:value="item.id"
|
|
||||||
/>
|
|
||||||
</el-select>
|
|
||||||
</el-form-item>
|
|
||||||
</el-col>
|
|
||||||
|
|
||||||
<el-col :span="12" class="mb20">
|
<el-col :span="12" class="mb20">
|
||||||
<el-form-item label="分类名称" prop="name">
|
<el-form-item label="分类名称" prop="name">
|
||||||
<el-input v-model="form.name" placeholder="请输入分类名称"/>
|
<el-input v-model="form.name" placeholder="请输入分类名称" />
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
</el-col>
|
</el-col>
|
||||||
|
|
||||||
<el-col :span="12" class="mb20">
|
<el-col :span="12" class="mb20">
|
||||||
<el-form-item label="排序" prop="sort">
|
<el-form-item label="排序" prop="sort">
|
||||||
<el-input-number :min="1" :max="1000" v-model="form.sort" placeholder="请输入排序"></el-input-number>
|
<el-input-number :min="1" :max="1000" v-model="form.sort" placeholder="请输入排序"></el-input-number>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
</el-col>
|
</el-col>
|
||||||
|
|
||||||
<el-col :span="12" class="mb20">
|
<el-col :span="12" class="mb20">
|
||||||
<el-form-item label="状态(0正常,1下架)" prop="status">
|
<el-form-item label="状态" prop="status">
|
||||||
<el-radio-group v-model="form.status">
|
<el-radio-group v-model="form.status">
|
||||||
<el-radio :label="item.value" v-for="(item, index) in status" border :key="index">{{ item.label }}
|
<el-radio :label="item.value" v-for="(item, index) in status" border :key="index">{{ item.label }}</el-radio>
|
||||||
</el-radio>
|
</el-radio-group>
|
||||||
</el-radio-group>
|
</el-form-item>
|
||||||
</el-form-item>
|
</el-col>
|
||||||
</el-col>
|
|
||||||
|
|
||||||
<el-col :span="12" class="mb20">
|
|
||||||
<el-form-item label="分类图片" prop="picUrl">
|
|
||||||
<upload-img v-model="form.picUrl"></upload-img>
|
|
||||||
</el-form-item>
|
|
||||||
</el-col>
|
|
||||||
|
|
||||||
|
<el-col :span="12" class="mb20">
|
||||||
|
<el-form-item label="分类图片" prop="picUrl">
|
||||||
|
<upload-img v-model:imageUrl="form.picUrl"></upload-img>
|
||||||
|
</el-form-item>
|
||||||
|
</el-col>
|
||||||
</el-row>
|
</el-row>
|
||||||
</el-form>
|
</el-form>
|
||||||
<template #footer>
|
<template #footer>
|
||||||
<span class="dialog-footer">
|
<span class="dialog-footer">
|
||||||
<el-button @click="visible = false">取消</el-button>
|
<el-button @click="visible = false">取消</el-button>
|
||||||
<el-button type="primary" @click="onSubmit" :disabled="loading">确认</el-button>
|
<el-button type="primary" @click="onSubmit" :disabled="loading">确认</el-button>
|
||||||
</span>
|
</span>
|
||||||
</template>
|
</template>
|
||||||
</el-dialog>
|
</el-dialog>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts" name="ShopCategoryDialog">
|
<script setup lang="ts" name="ShopCategoryDialog">
|
||||||
import { useDict } from '/@/hooks/dict';
|
import { useDict } from "/@/hooks/dict"
|
||||||
import { useMessage } from "/@/hooks/message";
|
import { useMessage } from "/@/hooks/message"
|
||||||
import { getObj, addObj, putObj, fetchList } from '/@/api/supermarket/shopCategory'
|
import { getObj, addObj, putObj, fetchList } from "/@/api/supermarket/shopCategory"
|
||||||
import { rule } from '/@/utils/validate';
|
import { rule } from "/@/utils/validate"
|
||||||
import { ref, reactive, nextTick, onMounted } from 'vue';
|
import { ref, reactive, nextTick, onMounted } from "vue"
|
||||||
const emit = defineEmits(['refresh']);
|
const emit = defineEmits(["refresh"])
|
||||||
|
|
||||||
// 定义变量内容
|
// 定义变量内容
|
||||||
const dataFormRef = ref();
|
const dataFormRef = ref()
|
||||||
const visible = ref(false)
|
const visible = ref(false)
|
||||||
const loading = ref(false)
|
const loading = ref(false)
|
||||||
// 定义字典
|
// 定义字典
|
||||||
const { status } = useDict('status')
|
const { status } = useDict("status")
|
||||||
|
|
||||||
// 提交表单数据
|
// 提交表单数据
|
||||||
const form = reactive({
|
const form = reactive({
|
||||||
id:'',
|
id: "",
|
||||||
parentId: '',
|
parentId: "",
|
||||||
name: '',
|
name: "",
|
||||||
sort: 0,
|
sort: 0,
|
||||||
status: '0',
|
status: "0",
|
||||||
picUrl: '',
|
picUrl: "",
|
||||||
});
|
})
|
||||||
|
|
||||||
// 定义校验规则
|
// 定义校验规则
|
||||||
const dataRules = ref({
|
const dataRules = ref({
|
||||||
name: [{required: true, message: '分类名称不能为空', trigger: 'blur'}],
|
name: [{ required: true, message: "分类名称不能为空", trigger: "blur" }],
|
||||||
})
|
})
|
||||||
|
|
||||||
// 分类选项
|
// 分类选项
|
||||||
const categoryOptions = ref<any[]>([]);
|
const categoryOptions = ref<any[]>([])
|
||||||
|
|
||||||
// 获取所有分类(排除自身)
|
// 获取所有分类(排除自身)
|
||||||
const loadCategories = async () => {
|
const loadCategories = async () => {
|
||||||
const res = await fetchList({ size: 9999 });
|
const res = await fetchList({ size: 9999 })
|
||||||
if (res && res.data && res.data.records) {
|
if (res && res.data && res.data.records) {
|
||||||
// 排除自己,避免自己作为自己的父级
|
// 排除自己,避免自己作为自己的父级
|
||||||
categoryOptions.value = res.data.records.filter((item: any) => item.id !== form.id);
|
categoryOptions.value = res.data.records.filter((item: any) => item.id !== form.id)
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
loadCategories();
|
loadCategories()
|
||||||
});
|
})
|
||||||
|
|
||||||
// 打开弹窗
|
// 打开弹窗
|
||||||
const openDialog = (id: string) => {
|
const openDialog = (id: string) => {
|
||||||
visible.value = true
|
visible.value = true
|
||||||
form.id = ''
|
form.id = ""
|
||||||
|
|
||||||
// 重置表单数据
|
// 重置表单数据
|
||||||
nextTick(() => {
|
nextTick(() => {
|
||||||
dataFormRef.value?.resetFields();
|
dataFormRef.value?.resetFields()
|
||||||
form.status = '0';
|
form.status = "0"
|
||||||
});
|
})
|
||||||
|
|
||||||
// 获取shopCategory信息
|
// 获取shopCategory信息
|
||||||
if (id) {
|
if (id) {
|
||||||
form.id = id
|
form.id = id
|
||||||
getshopCategoryData(id)
|
getshopCategoryData(id)
|
||||||
} else {
|
} else {
|
||||||
// 新增时直接加载分类
|
// 新增时直接加载分类
|
||||||
loadCategories();
|
loadCategories()
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
|
|
||||||
// 提交
|
// 提交
|
||||||
const onSubmit = async () => {
|
const onSubmit = async () => {
|
||||||
const valid = await dataFormRef.value.validate().catch(() => {});
|
const valid = await dataFormRef.value.validate().catch(() => {})
|
||||||
if (!valid) return false;
|
if (!valid) return false
|
||||||
|
|
||||||
try {
|
try {
|
||||||
loading.value = true;
|
loading.value = true
|
||||||
form.id ? await putObj(form) : await addObj(form);
|
form.id ? await putObj(form) : await addObj(form)
|
||||||
useMessage().success(form.id ? '修改成功' : '添加成功');
|
useMessage().success(form.id ? "修改成功" : "添加成功")
|
||||||
visible.value = false;
|
visible.value = false
|
||||||
emit('refresh');
|
emit("refresh")
|
||||||
} catch (err: any) {
|
} catch (err: any) {
|
||||||
useMessage().error(err.msg);
|
useMessage().error(err.msg)
|
||||||
} finally {
|
} finally {
|
||||||
loading.value = false;
|
loading.value = false
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
|
|
||||||
|
|
||||||
// 初始化表单数据
|
// 初始化表单数据
|
||||||
const getshopCategoryData = (id: string) => {
|
const getshopCategoryData = (id: string) => {
|
||||||
// 获取数据
|
// 获取数据
|
||||||
loading.value = true
|
loading.value = true
|
||||||
getObj(id).then((res: any) => {
|
getObj(id)
|
||||||
Object.assign(form, res.data)
|
.then((res: any) => {
|
||||||
// 编辑时加载分类并排除自己
|
Object.assign(form, res.data, { status: res.data.status.toString() })
|
||||||
loadCategories();
|
// 编辑时加载分类并排除自己
|
||||||
}).finally(() => {
|
loadCategories()
|
||||||
loading.value = false
|
})
|
||||||
})
|
.finally(() => {
|
||||||
};
|
loading.value = false
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
// 暴露变量
|
// 暴露变量
|
||||||
defineExpose({
|
defineExpose({
|
||||||
openDialog
|
openDialog,
|
||||||
});
|
})
|
||||||
</script>
|
</script>
|
||||||
@@ -1,84 +1,110 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="layout-padding">
|
<div class="layout-padding">
|
||||||
<div class="layout-padding-auto layout-padding-view">
|
<div class="layout-padding-auto layout-padding-view">
|
||||||
<el-row v-show="showSearch">
|
<el-row v-show="showSearch">
|
||||||
<el-form :model="state.queryForm" ref="queryRef" :inline="true" @keyup.enter="getDataList">
|
<el-form :model="state.queryForm" ref="queryRef" :inline="true" @keyup.enter="getDataList">
|
||||||
<el-form-item label="分类名称" prop="name" >
|
<el-form-item label="分类名称" prop="name">
|
||||||
<el-input placeholder="请输入分类名称" v-model="state.queryForm.name" />
|
<el-input placeholder="请输入分类名称" v-model="state.queryForm.name" />
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item>
|
<el-form-item>
|
||||||
<el-button icon="search" type="primary" @click="getDataList">
|
<el-button icon="search" type="primary" @click="getDataList"> 查询 </el-button>
|
||||||
查询
|
<el-button icon="Refresh" @click="resetQuery">重置</el-button>
|
||||||
</el-button>
|
</el-form-item>
|
||||||
<el-button icon="Refresh" @click="resetQuery">重置</el-button>
|
</el-form>
|
||||||
</el-form-item>
|
</el-row>
|
||||||
</el-form>
|
<el-row>
|
||||||
</el-row>
|
<div class="mb8" style="width: 100%">
|
||||||
<el-row>
|
<el-button
|
||||||
<div class="mb8" style="width: 100%">
|
icon="folder-add"
|
||||||
<el-button icon="folder-add" type="primary" class="ml10" @click="formDialogRef.openDialog()"
|
type="primary"
|
||||||
v-auth="'supermarket_shopCategory_add'">
|
class="ml10"
|
||||||
新 增
|
@click="formDialogRef.openDialog()"
|
||||||
</el-button>
|
v-auth="'supermarket_shopCategory_add'"
|
||||||
<el-button plain :disabled="multiple" icon="Delete" type="primary"
|
>
|
||||||
v-auth="'supermarket_shopCategory_del'" @click="handleDelete(selectObjs)">
|
新 增
|
||||||
删除
|
</el-button>
|
||||||
</el-button>
|
<el-button
|
||||||
<right-toolbar v-model:showSearch="showSearch" :export="'supermarket_shopCategory_export'"
|
plain
|
||||||
@exportExcel="exportExcel" class="ml10 mr20" style="float: right;"
|
:disabled="multiple"
|
||||||
@queryTable="getDataList"></right-toolbar>
|
icon="Delete"
|
||||||
</div>
|
type="primary"
|
||||||
</el-row>
|
v-auth="'supermarket_shopCategory_del'"
|
||||||
<el-table
|
@click="handleDelete(selectObjs)"
|
||||||
:data="treeData"
|
>
|
||||||
row-key="id"
|
删除
|
||||||
:tree-props="{ children: 'children' }"
|
</el-button>
|
||||||
v-loading="state.loading"
|
<right-toolbar
|
||||||
border
|
v-model:showSearch="showSearch"
|
||||||
:cell-style="tableStyle.cellStyle"
|
:export="'supermarket_shopCategory_export'"
|
||||||
:header-cell-style="tableStyle.headerCellStyle"
|
@exportExcel="exportExcel"
|
||||||
@selection-change="selectionChangHandle"
|
class="ml10 mr20"
|
||||||
@sort-change="sortChangeHandle"
|
style="float: right"
|
||||||
>
|
@queryTable="getDataList"
|
||||||
<el-table-column type="selection" width="40" align="center" />
|
></right-toolbar>
|
||||||
<el-table-column type="index" label="#" width="40" />
|
</div>
|
||||||
<el-table-column prop="name" label="分类名称" show-overflow-tooltip/>
|
</el-row>
|
||||||
<el-table-column prop="sort" label="排序" show-overflow-tooltip/>
|
<el-table
|
||||||
<el-table-column prop="status" label="状态(0正常,1下架)" show-overflow-tooltip>
|
:data="treeData"
|
||||||
<template #default="scope">
|
row-key="id"
|
||||||
<dict-tag :options="status" :value="scope.row.status"></dict-tag>
|
:tree-props="{ children: 'children' }"
|
||||||
</template>
|
v-loading="state.loading"
|
||||||
</el-table-column>
|
border
|
||||||
<el-table-column prop="picUrl" label="分类图片" show-overflow-tooltip/>
|
:cell-style="tableStyle.cellStyle"
|
||||||
<el-table-column label="操作" width="150">
|
:header-cell-style="tableStyle.headerCellStyle"
|
||||||
<template #default="scope">
|
@selection-change="selectionChangHandle"
|
||||||
<el-button icon="edit-pen" text type="primary" v-auth="'supermarket_shopCategory_edit'"
|
@sort-change="sortChangeHandle"
|
||||||
@click="formDialogRef.openDialog(scope.row.id)">编辑</el-button>
|
>
|
||||||
<el-button icon="delete" text type="primary" v-auth="'supermarket_shopCategory_del'" @click="handleDelete([scope.row.id])">删除</el-button>
|
<el-table-column type="selection" width="40" align="center" />
|
||||||
</template>
|
<el-table-column type="index" label="#" width="40" />
|
||||||
</el-table-column>
|
<el-table-column prop="name" label="分类名称" show-overflow-tooltip />
|
||||||
</el-table>
|
<el-table-column prop="sort" label="排序" show-overflow-tooltip />
|
||||||
<!-- <pagination @size-change="sizeChangeHandle" @current-change="currentChangeHandle" v-bind="state.pagination" /> -->
|
<el-table-column prop="status" label="状态" show-overflow-tooltip>
|
||||||
</div>
|
<template #default="scope">
|
||||||
|
<dict-tag :options="status" :value="scope.row.status"></dict-tag>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
<el-table-column prop="picUrl" label="分类图片" show-overflow-tooltip>
|
||||||
|
<template #default="scope">
|
||||||
|
<preview-image :src="scope.row.picUrl" />
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
<el-table-column label="操作" width="150">
|
||||||
|
<template #default="scope">
|
||||||
|
<el-button
|
||||||
|
icon="edit-pen"
|
||||||
|
text
|
||||||
|
type="primary"
|
||||||
|
v-auth="'supermarket_shopCategory_edit'"
|
||||||
|
@click="formDialogRef.openDialog(scope.row.id)"
|
||||||
|
>
|
||||||
|
编辑
|
||||||
|
</el-button>
|
||||||
|
<el-button icon="delete" text type="primary" v-auth="'supermarket_shopCategory_del'" @click="handleDelete([scope.row.id])">
|
||||||
|
删除
|
||||||
|
</el-button>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
</el-table>
|
||||||
|
<!-- <pagination @size-change="sizeChangeHandle" @current-change="currentChangeHandle" v-bind="state.pagination" /> -->
|
||||||
|
</div>
|
||||||
|
|
||||||
<!-- 编辑、新增 -->
|
<!-- 编辑、新增 -->
|
||||||
<form-dialog ref="formDialogRef" @refresh="getDataList()" />
|
<form-dialog ref="formDialogRef" @refresh="getDataList()" />
|
||||||
|
</div>
|
||||||
</div>
|
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts" name="systemShopCategory">
|
<script setup lang="ts" name="systemShopCategory">
|
||||||
import { BasicTableProps, useTable } from "/@/hooks/table";
|
import { BasicTableProps, useTable } from "/@/hooks/table"
|
||||||
import { fetchList, delObjs, tree as fetchTree, putObj } from "/@/api/supermarket/shopCategory";
|
import { fetchList, delObjs, tree as fetchTree, putObj } from "/@/api/supermarket/shopCategory"
|
||||||
import { useMessage, useMessageBox } from "/@/hooks/message";
|
import { useMessage, useMessageBox } from "/@/hooks/message"
|
||||||
import { useDict } from '/@/hooks/dict';
|
import { useDict } from "/@/hooks/dict"
|
||||||
import { ref, reactive, onMounted, defineExpose } from 'vue';
|
import { ref, reactive, onMounted, defineExpose } from "vue"
|
||||||
|
|
||||||
// 引入组件
|
// 引入组件
|
||||||
const FormDialog = defineAsyncComponent(() => import('./form.vue'));
|
const FormDialog = defineAsyncComponent(() => import("./form.vue"))
|
||||||
// 定义查询字典
|
// 定义查询字典
|
||||||
|
|
||||||
const { status } = useDict('status')
|
const { status } = useDict("status")
|
||||||
// 定义变量内容
|
// 定义变量内容
|
||||||
const formDialogRef = ref()
|
const formDialogRef = ref()
|
||||||
// 搜索变量
|
// 搜索变量
|
||||||
@@ -89,91 +115,85 @@ const selectObjs = ref([]) as any
|
|||||||
const multiple = ref(true)
|
const multiple = ref(true)
|
||||||
|
|
||||||
const state: BasicTableProps = reactive<BasicTableProps>({
|
const state: BasicTableProps = reactive<BasicTableProps>({
|
||||||
queryForm: {},
|
queryForm: {},
|
||||||
pageList: fetchList,
|
pageList: fetchList,
|
||||||
loading: false,
|
loading: false,
|
||||||
pagination: { total: 0 }
|
pagination: { total: 0 },
|
||||||
})
|
})
|
||||||
|
|
||||||
const treeData = ref<any[]>([])
|
const treeData = ref<any[]>([])
|
||||||
|
|
||||||
function listToTree(list: any[]): any[] {
|
function listToTree(list: any[]): any[] {
|
||||||
const map = new Map<string, any>();
|
const map = new Map<string, any>()
|
||||||
list.forEach((item: any) => {
|
list.forEach((item: any) => {
|
||||||
item.children = [];
|
item.children = []
|
||||||
map.set(item.id, item);
|
map.set(item.id, item)
|
||||||
});
|
})
|
||||||
const tree: any[] = [];
|
const tree: any[] = []
|
||||||
list.forEach((item: any) => {
|
list.forEach((item: any) => {
|
||||||
if (item.parentId && item.parentId !== '0' && map.has(item.parentId)) {
|
if (item.parentId && item.parentId !== "0" && map.has(item.parentId)) {
|
||||||
map.get(item.parentId).children.push(item);
|
map.get(item.parentId).children.push(item)
|
||||||
} else {
|
} else {
|
||||||
tree.push(item);
|
tree.push(item)
|
||||||
}
|
}
|
||||||
});
|
})
|
||||||
return tree;
|
return tree
|
||||||
}
|
}
|
||||||
|
|
||||||
const getDataList = async () => {
|
const getDataList = async () => {
|
||||||
state.loading = true;
|
state.loading = true
|
||||||
try {
|
try {
|
||||||
const res = await fetchTree();
|
const res = await fetchTree()
|
||||||
treeData.value = res.data || [];
|
treeData.value = res.data || []
|
||||||
(state.pagination as any).total = Array.isArray(res.data) ? res.data.length : 0;
|
;(state.pagination as any).total = Array.isArray(res.data) ? res.data.length : 0
|
||||||
} finally {
|
} finally {
|
||||||
state.loading = false;
|
state.loading = false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
getDataList();
|
getDataList()
|
||||||
})
|
})
|
||||||
|
|
||||||
// table hook
|
// table hook
|
||||||
const {
|
const { currentChangeHandle, sizeChangeHandle, sortChangeHandle, downBlobFile, tableStyle } = useTable(state)
|
||||||
currentChangeHandle,
|
|
||||||
sizeChangeHandle,
|
|
||||||
sortChangeHandle,
|
|
||||||
downBlobFile,
|
|
||||||
tableStyle
|
|
||||||
} = useTable(state)
|
|
||||||
|
|
||||||
// 清空搜索条件
|
// 清空搜索条件
|
||||||
const resetQuery = () => {
|
const resetQuery = () => {
|
||||||
queryRef.value?.resetFields()
|
queryRef.value?.resetFields()
|
||||||
selectObjs.value = []
|
selectObjs.value = []
|
||||||
getDataList()
|
getDataList()
|
||||||
}
|
}
|
||||||
|
|
||||||
// 导出excel
|
// 导出excel
|
||||||
const exportExcel = () => {
|
const exportExcel = () => {
|
||||||
downBlobFile('/supermarket/shopCategory/export', Object.assign(state.queryForm, { ids: selectObjs }), 'shopCategory.xlsx')
|
downBlobFile("/supermarket/shopCategory/export", Object.assign(state.queryForm, { ids: selectObjs }), "shopCategory.xlsx")
|
||||||
}
|
}
|
||||||
|
|
||||||
// 多选事件
|
// 多选事件
|
||||||
const selectionChangHandle = (objs: { id: string }[]) => {
|
const selectionChangHandle = (objs: { id: string }[]) => {
|
||||||
selectObjs.value = objs.map(({ id }) => id);
|
selectObjs.value = objs.map(({ id }) => id)
|
||||||
multiple.value = !objs.length;
|
multiple.value = !objs.length
|
||||||
};
|
}
|
||||||
|
|
||||||
// 删除操作
|
// 删除操作
|
||||||
const handleDelete = async (ids: string[]) => {
|
const handleDelete = async (ids: string[]) => {
|
||||||
try {
|
try {
|
||||||
await useMessageBox().confirm('此操作将永久删除');
|
await useMessageBox().confirm("此操作将永久删除")
|
||||||
} catch {
|
} catch {
|
||||||
return;
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
await delObjs(ids);
|
await delObjs(ids)
|
||||||
getDataList();
|
getDataList()
|
||||||
useMessage().success('删除成功');
|
useMessage().success("删除成功")
|
||||||
} catch (err: any) {
|
} catch (err: any) {
|
||||||
useMessage().error(err.msg);
|
useMessage().error(err.msg)
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
|
|
||||||
defineExpose({
|
defineExpose({
|
||||||
treeData
|
treeData,
|
||||||
});
|
})
|
||||||
</script>
|
</script>
|
||||||
@@ -1,65 +1,99 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="layout-padding">
|
<div class="layout-padding">
|
||||||
<div class="layout-padding-auto layout-padding-view">
|
<div class="layout-padding-auto layout-padding-view">
|
||||||
<el-row>
|
<el-row>
|
||||||
<div class="mb8" style="width: 100%">
|
<div class="mb8" style="width: 100%">
|
||||||
<el-button icon="folder-add" type="primary" class="ml10" @click="formDialogRef.openDialog()"
|
<!-- <el-button icon="folder-add" type="primary" class="ml10" @click="formDialogRef.openDialog()" v-auth="'supermarket_shopSku_add'">
|
||||||
v-auth="'supermarket_shopSku_add'">
|
新 增
|
||||||
新 增
|
</el-button> -->
|
||||||
</el-button>
|
<el-button
|
||||||
<el-button plain :disabled="multiple" icon="Delete" type="primary"
|
plain
|
||||||
v-auth="'supermarket_shopSku_del'" @click="handleDelete(selectObjs)">
|
:disabled="multiple"
|
||||||
删除
|
icon="Delete"
|
||||||
</el-button>
|
type="primary"
|
||||||
<right-toolbar v-model:showSearch="showSearch" :export="'supermarket_shopSku_export'"
|
v-auth="'supermarket_shopSku_del'"
|
||||||
@exportExcel="exportExcel" class="ml10 mr20" style="float: right;"
|
@click="handleDelete(selectObjs)"
|
||||||
@queryTable="getDataList"></right-toolbar>
|
>
|
||||||
</div>
|
删 除
|
||||||
</el-row>
|
</el-button>
|
||||||
<el-table :data="state.dataList" v-loading="state.loading" border
|
<right-toolbar
|
||||||
:cell-style="tableStyle.cellStyle" :header-cell-style="tableStyle.headerCellStyle"
|
v-model:showSearch="showSearch"
|
||||||
|
:export="'supermarket_shopSku_export'"
|
||||||
|
@exportExcel="exportExcel"
|
||||||
|
class="ml10 mr20"
|
||||||
|
style="float: right"
|
||||||
|
@queryTable="getDataList"
|
||||||
|
></right-toolbar>
|
||||||
|
</div>
|
||||||
|
</el-row>
|
||||||
|
<el-table
|
||||||
|
:data="state.dataList"
|
||||||
|
v-loading="state.loading"
|
||||||
|
border
|
||||||
|
:cell-style="tableStyle.cellStyle"
|
||||||
|
:header-cell-style="tableStyle.headerCellStyle"
|
||||||
@selection-change="selectionChangHandle"
|
@selection-change="selectionChangHandle"
|
||||||
@sort-change="sortChangeHandle">
|
@sort-change="sortChangeHandle"
|
||||||
<el-table-column type="selection" width="40" align="center" />
|
>
|
||||||
<el-table-column type="index" label="#" width="40" />
|
<el-table-column type="selection" width="40" align="center" />
|
||||||
<el-table-column prop="barCode" label="条码" show-overflow-tooltip/>
|
<el-table-column type="index" label="#" width="40" />
|
||||||
<el-table-column prop="spec" label="规格" show-overflow-tooltip/>
|
<el-table-column prop="barCode" label="条码" show-overflow-tooltip />
|
||||||
<el-table-column prop="unit" label="单位" show-overflow-tooltip/>
|
<el-table-column prop="spec" label="规格" show-overflow-tooltip />
|
||||||
<el-table-column prop="status" label="状态(0正常,1停销)" show-overflow-tooltip/>
|
<el-table-column prop="unit" label="单位" show-overflow-tooltip />
|
||||||
<el-table-column prop="purchasePrice" label="进价/单位分" show-overflow-tooltip/>
|
<el-table-column prop="status" label="状态" show-overflow-tooltip>
|
||||||
<el-table-column prop="retailPrice" label="零售价/单位分" show-overflow-tooltip/>
|
<template #default="scope">
|
||||||
<el-table-column prop="spuId" label="spuID" show-overflow-tooltip/>
|
<dict-tag :options="status" :value="scope.row.status"></dict-tag>
|
||||||
<el-table-column prop="promotionPrice" label="促销价" show-overflow-tooltip/>
|
</template>
|
||||||
<el-table-column prop="stock" label="库存" show-overflow-tooltip/>
|
</el-table-column>
|
||||||
<el-table-column prop="attribute" label="sku属性" show-overflow-tooltip/>
|
<!-- <el-table-column prop="purchasePrice" label="进价/单位分" show-overflow-tooltip /> -->
|
||||||
<el-table-column label="操作" width="150">
|
<el-table-column prop="retailPrice" label="零售价(分)" show-overflow-tooltip>
|
||||||
<template #default="scope">
|
<template #default="{ row }">
|
||||||
<el-button icon="edit-pen" text type="primary" v-auth="'supermarket_shopSku_edit'"
|
{{ displayPrice(row.retailPrice, "") }}
|
||||||
@click="formDialogRef.openDialog(scope.row.id)">编辑</el-button>
|
</template>
|
||||||
<el-button icon="delete" text type="primary" v-auth="'supermarket_shopSku_del'" @click="handleDelete([scope.row.id])">删除</el-button>
|
</el-table-column>
|
||||||
</template>
|
<el-table-column prop="promotionPrice" label="促销价" show-overflow-tooltip>
|
||||||
</el-table-column>
|
<template #default="{ row }">
|
||||||
</el-table>
|
{{ displayPrice(row.promotionPrice, "") }}
|
||||||
<pagination @size-change="sizeChangeHandle" @current-change="currentChangeHandle" v-bind="state.pagination" />
|
</template>
|
||||||
</div>
|
</el-table-column>
|
||||||
|
<el-table-column prop="stock" label="库存" show-overflow-tooltip />
|
||||||
|
<el-table-column prop="attribute" label="口味" show-overflow-tooltip />
|
||||||
|
<el-table-column label="操作" width="150">
|
||||||
|
<template #default="scope">
|
||||||
|
<el-button
|
||||||
|
icon="edit-pen"
|
||||||
|
text
|
||||||
|
type="primary"
|
||||||
|
v-auth="'supermarket_shopSku_edit'"
|
||||||
|
@click="formDialogRef.openDialog(scope.row.id)"
|
||||||
|
>
|
||||||
|
编辑
|
||||||
|
</el-button>
|
||||||
|
<el-button icon="delete" text type="primary" v-auth="'supermarket_shopSku_del'" @click="handleDelete([scope.row.id])">
|
||||||
|
删除
|
||||||
|
</el-button>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
</el-table>
|
||||||
|
<pagination @size-change="sizeChangeHandle" @current-change="currentChangeHandle" v-bind="state.pagination" />
|
||||||
|
</div>
|
||||||
|
|
||||||
<!-- 编辑、新增 -->
|
<!-- 编辑、新增 -->
|
||||||
<form-dialog ref="formDialogRef" @refresh="getDataList(false)" />
|
<form-dialog ref="formDialogRef" @refresh="getDataList(false)" />
|
||||||
|
</div>
|
||||||
</div>
|
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts" name="systemShopSku">
|
<script setup lang="ts" name="systemShopSku">
|
||||||
import { BasicTableProps, useTable } from "/@/hooks/table";
|
import { BasicTableProps, useTable } from "/@/hooks/table"
|
||||||
import { fetchList, delObjs } from "/@/api/supermarket/shopSku";
|
import { fetchList, delObjs } from "/@/api/supermarket/shopSku"
|
||||||
import { useMessage, useMessageBox } from "/@/hooks/message";
|
import { useMessage, useMessageBox } from "/@/hooks/message"
|
||||||
import { useDict } from '/@/hooks/dict';
|
import { useDict } from "/@/hooks/dict"
|
||||||
|
import { displayPrice } from "/@/utils/formatMoney"
|
||||||
|
|
||||||
// 引入组件
|
const { status } = useDict("status")
|
||||||
const FormDialog = defineAsyncComponent(() => import('./form.vue'));
|
|
||||||
// 定义查询字典
|
const FormDialog = defineAsyncComponent(() => import("./form.vue"))
|
||||||
|
|
||||||
// 定义变量内容
|
|
||||||
const formDialogRef = ref()
|
const formDialogRef = ref()
|
||||||
// 搜索变量
|
// 搜索变量
|
||||||
const queryRef = ref()
|
const queryRef = ref()
|
||||||
@@ -69,54 +103,47 @@ const selectObjs = ref([]) as any
|
|||||||
const multiple = ref(true)
|
const multiple = ref(true)
|
||||||
|
|
||||||
const state: BasicTableProps = reactive<BasicTableProps>({
|
const state: BasicTableProps = reactive<BasicTableProps>({
|
||||||
queryForm: {},
|
queryForm: {},
|
||||||
pageList: fetchList
|
pageList: fetchList,
|
||||||
})
|
})
|
||||||
|
|
||||||
// table hook
|
// table hook
|
||||||
const {
|
const { getDataList, currentChangeHandle, sizeChangeHandle, sortChangeHandle, downBlobFile, tableStyle } = useTable(state)
|
||||||
getDataList,
|
|
||||||
currentChangeHandle,
|
|
||||||
sizeChangeHandle,
|
|
||||||
sortChangeHandle,
|
|
||||||
downBlobFile,
|
|
||||||
tableStyle
|
|
||||||
} = useTable(state)
|
|
||||||
|
|
||||||
// 清空搜索条件
|
// 清空搜索条件
|
||||||
const resetQuery = () => {
|
const resetQuery = () => {
|
||||||
// 清空搜索条件
|
// 清空搜索条件
|
||||||
queryRef.value?.resetFields()
|
queryRef.value?.resetFields()
|
||||||
// 清空多选
|
// 清空多选
|
||||||
selectObjs.value = []
|
selectObjs.value = []
|
||||||
getDataList()
|
getDataList()
|
||||||
}
|
}
|
||||||
|
|
||||||
// 导出excel
|
// 导出excel
|
||||||
const exportExcel = () => {
|
const exportExcel = () => {
|
||||||
downBlobFile('/supermarket/shopSku/export', Object.assign(state.queryForm, { ids: selectObjs }), 'shopSku.xlsx')
|
downBlobFile("/supermarket/shopSku/export", Object.assign(state.queryForm, { ids: selectObjs }), "shopSku.xlsx")
|
||||||
}
|
}
|
||||||
|
|
||||||
// 多选事件
|
// 多选事件
|
||||||
const selectionChangHandle = (objs: { id: string }[]) => {
|
const selectionChangHandle = (objs: { id: string }[]) => {
|
||||||
selectObjs.value = objs.map(({ id }) => id);
|
selectObjs.value = objs.map(({ id }) => id)
|
||||||
multiple.value = !objs.length;
|
multiple.value = !objs.length
|
||||||
};
|
}
|
||||||
|
|
||||||
// 删除操作
|
// 删除操作
|
||||||
const handleDelete = async (ids: string[]) => {
|
const handleDelete = async (ids: string[]) => {
|
||||||
try {
|
try {
|
||||||
await useMessageBox().confirm('此操作将永久删除');
|
await useMessageBox().confirm("此操作将永久删除")
|
||||||
} catch {
|
} catch {
|
||||||
return;
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
await delObjs(ids);
|
await delObjs(ids)
|
||||||
getDataList();
|
getDataList()
|
||||||
useMessage().success('删除成功');
|
useMessage().success("删除成功")
|
||||||
} catch (err: any) {
|
} catch (err: any) {
|
||||||
useMessage().error(err.msg);
|
useMessage().error(err.msg)
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
</script>
|
</script>
|
||||||
@@ -1,505 +1,514 @@
|
|||||||
<template>
|
<template>
|
||||||
<el-dialog :title="form.id ? '编辑' : '新增'" v-model="visible"
|
<el-dialog :title="form.id ? '编辑' : '新增'" v-model="visible" :close-on-click-modal="false" draggable width="1100px">
|
||||||
:close-on-click-modal="false" draggable
|
<el-tabs v-model="activeTab" type="card" style="margin-bottom: 24px" :before-leave="handleTabLeave">
|
||||||
width="1100px">
|
<el-tab-pane label="基本信息" name="base">
|
||||||
<el-tabs v-model="activeTab" type="card" style="margin-bottom: 24px;" :before-leave="handleTabLeave">
|
<el-form ref="dataFormRef" :model="form" :rules="dataRules" formDialogRef label-width="90px" v-loading="loading">
|
||||||
<el-tab-pane label="基本信息" name="base">
|
<el-row :gutter="24">
|
||||||
<el-form ref="dataFormRef" :model="form" :rules="dataRules" formDialogRef label-width="90px" v-loading="loading">
|
<!-- 基本信息必填项 -->
|
||||||
<el-row :gutter="24">
|
<el-col :span="12" class="mb20">
|
||||||
<!-- 基本信息必填项 -->
|
<el-form-item label="货号" prop="productCode" required>
|
||||||
<el-col :span="12" class="mb20">
|
<el-input v-model="form.productCode" placeholder="请输入货号" />
|
||||||
<el-form-item label="货号" prop="productCode" required>
|
</el-form-item>
|
||||||
<el-input v-model="form.productCode" placeholder="请输入货号"/>
|
</el-col>
|
||||||
</el-form-item>
|
<el-col :span="12" class="mb20">
|
||||||
</el-col>
|
<el-form-item label="商品名称" prop="productName" required>
|
||||||
<el-col :span="12" class="mb20">
|
<el-input v-model="form.productName" placeholder="请输入商品名称" />
|
||||||
<el-form-item label="商品名称" prop="productName" required>
|
</el-form-item>
|
||||||
<el-input v-model="form.productName" placeholder="请输入商品名称"/>
|
</el-col>
|
||||||
</el-form-item>
|
<el-col :span="12" class="mb20">
|
||||||
</el-col>
|
<el-form-item label="商品分类" prop="categoryId" required>
|
||||||
<el-col :span="12" class="mb20">
|
<el-cascader
|
||||||
<el-form-item label="商品分类" prop="categoryId" required>
|
v-model="form.categoryId"
|
||||||
<el-cascader
|
:options="categoryOptions"
|
||||||
v-model="form.categoryId"
|
:props="{ value: 'id', label: 'name', children: 'children', checkStrictly: true }"
|
||||||
:options="categoryOptions"
|
clearable
|
||||||
:props="{ value: 'id', label: 'name', children: 'children', checkStrictly: true }"
|
placeholder="请选择商品分类"
|
||||||
clearable
|
/>
|
||||||
placeholder="请选择商品分类"
|
</el-form-item>
|
||||||
/>
|
</el-col>
|
||||||
</el-form-item>
|
<el-col :span="8" class="mb20">
|
||||||
</el-col>
|
<el-form-item label="商品性质" prop="productNature">
|
||||||
<el-col :span="8" class="mb20">
|
<el-select v-model="form.productNature" placeholder="请选择商品性质">
|
||||||
<el-form-item label="商品性质" prop="productNature">
|
<el-option :value="item.value" :label="item.label" v-for="(item, index) in supermarket_nature" :key="index" />
|
||||||
<el-select v-model="form.productNature" placeholder="请选择商品性质">
|
</el-select>
|
||||||
<el-option :value="item.value" :label="item.label" v-for="(item, index) in supermarket_nature" :key="index" />
|
</el-form-item>
|
||||||
</el-select>
|
</el-col>
|
||||||
</el-form-item>
|
<el-col :span="12" class="mb20">
|
||||||
</el-col>
|
<el-form-item label="商品封面图" prop="picUrl" required>
|
||||||
<el-col :span="24" class="mb20">
|
<upload-img v-model:imageUrl="form.picUrl"></upload-img>
|
||||||
<el-form-item label="商品封面图" prop="picUrl" required>
|
</el-form-item>
|
||||||
<upload-img v-model:imageUrl="form.picUrl"></upload-img>
|
</el-col>
|
||||||
</el-form-item>
|
<el-col :span="12" class="mb20">
|
||||||
</el-col>
|
<el-form-item label="商品状态" prop="status" required>
|
||||||
<el-col :span="24" class="mb20">
|
<el-radio-group v-model="form.status">
|
||||||
<el-form-item label="商品详情" prop="description">
|
<el-radio :label="item.value" v-for="(item, index) in status" border :key="index">{{ item.label }}</el-radio>
|
||||||
<editor v-if="visible" v-model:get-html="form.description" placeholder="请输入商品详情"></editor>
|
</el-radio-group>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
</el-col>
|
</el-col>
|
||||||
<el-col :span="12" class="mb20">
|
<el-col :span="24" class="mb20">
|
||||||
<el-form-item label="库存" prop="stock">
|
<el-form-item label="商品详情" prop="description">
|
||||||
<el-input-number :min="0" :max="1000" v-model="form.stock" placeholder="请输入库存"></el-input-number>
|
<editor v-if="visible" v-model:get-html="form.description" placeholder="请输入商品详情"></editor>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
</el-col>
|
</el-col>
|
||||||
<el-col :span="12" class="mb20">
|
<el-col :span="12" class="mb20">
|
||||||
<el-form-item label="单人限购数" prop="limitNum">
|
<el-form-item label="库存" prop="stock">
|
||||||
<el-input-number :min="1" :max="1000" v-model="form.limitNum" placeholder="请输入单人限购数量"></el-input-number>
|
<el-input-number :min="0" :max="1000" v-model="form.stock" placeholder="请输入库存"></el-input-number>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
</el-col>
|
</el-col>
|
||||||
</el-row>
|
<el-col :span="12" class="mb20">
|
||||||
</el-form>
|
<el-form-item label="单人限购数" prop="limitNum">
|
||||||
</el-tab-pane>
|
<el-input-number :min="1" :max="1000" v-model="form.limitNum" placeholder="请输入单人限购数量"></el-input-number>
|
||||||
<el-tab-pane label="SKU信息" name="sku">
|
</el-form-item>
|
||||||
<el-divider>SKU 列表</el-divider>
|
</el-col>
|
||||||
<el-table :data="form.skuList" style="width: 100%; min-width: 1000px; margin-bottom: 16px;" :header-cell-style="tableHeaderStyle">
|
</el-row>
|
||||||
<el-table-column prop="barCode" width="120">
|
</el-form>
|
||||||
<template #header>
|
</el-tab-pane>
|
||||||
<span class="required">*</span> 条码
|
<el-tab-pane label="SKU信息" name="sku">
|
||||||
</template>
|
<el-divider>SKU 列表</el-divider>
|
||||||
<template #default="scope">
|
<el-table :data="form.skuList" style="width: 100%; min-width: 1000px; margin-bottom: 16px" :header-cell-style="tableHeaderStyle">
|
||||||
<el-form-item
|
<el-table-column prop="barCode" width="120">
|
||||||
:prop="`skuList.${scope.$index}.barCode`"
|
<template #header> <span class="required">*</span> 条码 </template>
|
||||||
:rules="[{ required: true, message: '条码不能为空', trigger: 'blur' }]"
|
<template #default="scope">
|
||||||
>
|
<el-form-item
|
||||||
<el-input v-model="scope.row.barCode" placeholder="请输入条码" clearable />
|
:prop="`skuList.${scope.$index}.barCode`"
|
||||||
</el-form-item>
|
:rules="[{ required: true, message: '条码不能为空', trigger: 'blur' }]"
|
||||||
</template>
|
>
|
||||||
</el-table-column>
|
<el-input v-model="scope.row.barCode" placeholder="请输入条码" clearable />
|
||||||
<el-table-column prop="spec" width="100">
|
</el-form-item>
|
||||||
<template #header>规格</template>
|
</template>
|
||||||
<template #default="scope">
|
</el-table-column>
|
||||||
<el-input v-model="scope.row.spec" placeholder="请输入规格" />
|
<el-table-column prop="spec" width="100">
|
||||||
</template>
|
<template #header>规格</template>
|
||||||
</el-table-column>
|
<template #default="scope">
|
||||||
<el-table-column prop="unit" width="120">
|
<el-input v-model="scope.row.spec" placeholder="请输入规格" />
|
||||||
<template #header>
|
</template>
|
||||||
<span class="required">*</span> 单位
|
</el-table-column>
|
||||||
</template>
|
<el-table-column prop="unit" width="120">
|
||||||
<template #default="scope">
|
<template #header> <span class="required">*</span> 单位 </template>
|
||||||
<el-form-item
|
<template #default="scope">
|
||||||
:prop="`skuList.${scope.$index}.unit`"
|
<el-form-item :prop="`skuList.${scope.$index}.unit`" :rules="[{ required: true, message: '单位不能为空', trigger: 'blur' }]">
|
||||||
:rules="[{ required: true, message: '单位不能为空', trigger: 'blur' }]"
|
<el-input v-model="scope.row.unit" placeholder="请输入单位" clearable />
|
||||||
>
|
</el-form-item>
|
||||||
<el-input v-model="scope.row.unit" placeholder="请输入单位" clearable />
|
</template>
|
||||||
</el-form-item>
|
</el-table-column>
|
||||||
</template>
|
<el-table-column prop="status" width="100">
|
||||||
</el-table-column>
|
<template #header>状态</template>
|
||||||
<el-table-column prop="status" width="100">
|
<template #default="scope">
|
||||||
<template #header>状态</template>
|
<el-select v-model="scope.row.status" placeholder="请选择">
|
||||||
<template #default="scope">
|
<el-option label="正常" :value="0" />
|
||||||
<el-select v-model="scope.row.status" placeholder="请选择">
|
<el-option label="停销" :value="1" />
|
||||||
<el-option label="正常" :value="0" />
|
</el-select>
|
||||||
<el-option label="停销" :value="1" />
|
</template>
|
||||||
</el-select>
|
</el-table-column>
|
||||||
</template>
|
<el-table-column prop="retailPrice" width="140">
|
||||||
</el-table-column>
|
<template #header> <span class="required">*</span> 零售价 </template>
|
||||||
<el-table-column prop="retailPrice" width="140">
|
<template #default="scope">
|
||||||
<template #header>
|
<el-form-item
|
||||||
<span class="required">*</span> 零售价
|
:prop="`skuList.${scope.$index}.retailPrice`"
|
||||||
</template>
|
:rules="[{ required: true, message: '零售价不能为空', trigger: 'blur' }]"
|
||||||
<template #default="scope">
|
>
|
||||||
<el-form-item
|
<el-input v-model="scope.row.retailPrice" placeholder="零售价/单位分" clearable style="width: 80px" />
|
||||||
:prop="`skuList.${scope.$index}.retailPrice`"
|
<span style="margin-left: 4px; color: #888">元</span>
|
||||||
:rules="[{ required: true, message: '零售价不能为空', trigger: 'blur' }]"
|
</el-form-item>
|
||||||
>
|
</template>
|
||||||
<el-input v-model="scope.row.retailPrice" placeholder="零售价/单位分" clearable style="width: 80px;" />
|
</el-table-column>
|
||||||
<span style="margin-left: 4px; color: #888;">元</span>
|
<el-table-column prop="promotionPrice" width="140">
|
||||||
</el-form-item>
|
<template #header>促销价</template>
|
||||||
</template>
|
<template #default="scope">
|
||||||
</el-table-column>
|
<el-input v-model="scope.row.promotionPrice" placeholder="促销价" clearable style="width: 80px" />
|
||||||
<el-table-column prop="promotionPrice" width="140">
|
<span style="margin-left: 4px; color: #888">元</span>
|
||||||
<template #header>促销价</template>
|
</template>
|
||||||
<template #default="scope">
|
</el-table-column>
|
||||||
<el-input v-model="scope.row.promotionPrice" placeholder="促销价" clearable style="width: 80px;" />
|
<el-table-column prop="stock" width="120">
|
||||||
<span style="margin-left: 4px; color: #888;">元</span>
|
<template #header> <span class="required">*</span> 库存 </template>
|
||||||
</template>
|
<template #default="scope">
|
||||||
</el-table-column>
|
<el-form-item :prop="`skuList.${scope.$index}.stock`" :rules="[{ required: true, message: '库存不能为空', trigger: 'blur' }]">
|
||||||
<el-table-column prop="stock" width="120">
|
<el-input v-model="scope.row.stock" placeholder="库存" clearable />
|
||||||
<template #header>
|
</el-form-item>
|
||||||
<span class="required">*</span> 库存
|
</template>
|
||||||
</template>
|
</el-table-column>
|
||||||
<template #default="scope">
|
<el-table-column prop="attribute" width="120">
|
||||||
<el-form-item
|
<template #header>口味</template>
|
||||||
:prop="`skuList.${scope.$index}.stock`"
|
<template #default="scope">
|
||||||
:rules="[{ required: true, message: '库存不能为空', trigger: 'blur' }]"
|
<el-input v-model="scope.row.attribute" placeholder="口味" />
|
||||||
>
|
</template>
|
||||||
<el-input v-model="scope.row.stock" placeholder="库存" clearable />
|
</el-table-column>
|
||||||
</el-form-item>
|
<el-table-column label="操作" width="80">
|
||||||
</template>
|
<template #header>操作</template>
|
||||||
</el-table-column>
|
<template #default="scope">
|
||||||
<el-table-column prop="attribute" width="120">
|
<el-button type="danger" size="small" @click="removeSku(scope.$index)">删除</el-button>
|
||||||
<template #header>口味</template>
|
</template>
|
||||||
<template #default="scope">
|
</el-table-column>
|
||||||
<el-input v-model="scope.row.attribute" placeholder="口味" />
|
</el-table>
|
||||||
</template>
|
<el-button type="primary" @click="addSku">新增SKU</el-button>
|
||||||
</el-table-column>
|
</el-tab-pane>
|
||||||
<el-table-column label="操作" width="80">
|
<el-tab-pane label="在销商户" name="merchant">
|
||||||
<template #header>操作</template>
|
<el-button type="primary" @click="showMerchantDialog = true">选择在销商户</el-button>
|
||||||
<template #default="scope">
|
<el-table :data="selectedMerchants" style="margin-top: 16px">
|
||||||
<el-button type="danger" size="small" @click="removeSku(scope.$index)">删除</el-button>
|
<el-table-column prop="name" label="商户名称" />
|
||||||
</template>
|
<el-table-column prop="deptName" label="部门" />
|
||||||
</el-table-column>
|
<el-table-column label="操作" width="80">
|
||||||
</el-table>
|
<template #default="scope">
|
||||||
<el-button type="primary" @click="addSku">新增SKU</el-button>
|
<el-button type="danger" size="small" @click="removeMerchant(scope.$index)">移除</el-button>
|
||||||
</el-tab-pane>
|
</template>
|
||||||
<el-tab-pane label="在销商户" name="merchant">
|
</el-table-column>
|
||||||
<el-button type="primary" @click="showMerchantDialog = true">选择在销商户</el-button>
|
</el-table>
|
||||||
<el-table :data="selectedMerchants" style="margin-top: 16px;">
|
<el-dialog v-model="showMerchantDialog" title="选择在销商户" width="700px">
|
||||||
<el-table-column prop="name" label="商户名称" />
|
<el-input v-model="merchantSearch" placeholder="搜索商户名称" style="margin-bottom: 12px" @input="fetchMerchantList" />
|
||||||
<el-table-column prop="deptName" label="部门" />
|
<el-table
|
||||||
<el-table-column label="操作" width="80">
|
:data="merchantList"
|
||||||
<template #default="scope">
|
@selection-change="handleMerchantSelect"
|
||||||
<el-button type="danger" size="small" @click="removeMerchant(scope.$index)">移除</el-button>
|
:row-key="(row: Record<string, any>) => row.id"
|
||||||
</template>
|
height="400"
|
||||||
</el-table-column>
|
>
|
||||||
</el-table>
|
<el-table-column type="selection" width="40" />
|
||||||
<el-dialog v-model="showMerchantDialog" title="选择在销商户" width="700px">
|
<el-table-column prop="name" label="商户名称" />
|
||||||
<el-input v-model="merchantSearch" placeholder="搜索商户名称" style="margin-bottom: 12px;" @input="fetchMerchantList" />
|
<el-table-column prop="deptName" label="部门" />
|
||||||
<el-table :data="merchantList" @selection-change="handleMerchantSelect" :row-key="(row: Record<string, any>) => row.id" height="400">
|
</el-table>
|
||||||
<el-table-column type="selection" width="40" />
|
<template #footer>
|
||||||
<el-table-column prop="name" label="商户名称" />
|
<el-button @click="showMerchantDialog = false">取消</el-button>
|
||||||
<el-table-column prop="deptName" label="部门" />
|
<el-button type="primary" @click="confirmMerchantSelect">确定</el-button>
|
||||||
</el-table>
|
</template>
|
||||||
<template #footer>
|
</el-dialog>
|
||||||
<el-button @click="showMerchantDialog = false">取消</el-button>
|
</el-tab-pane>
|
||||||
<el-button type="primary" @click="confirmMerchantSelect">确定</el-button>
|
</el-tabs>
|
||||||
</template>
|
<template #footer>
|
||||||
</el-dialog>
|
<el-button v-if="activeTab === 'sku'" @click="activeTab = 'base'">上一步</el-button>
|
||||||
</el-tab-pane>
|
<el-button v-if="activeTab === 'merchant'" @click="activeTab = 'sku'">上一步</el-button>
|
||||||
</el-tabs>
|
<el-button v-if="activeTab === 'base'" type="primary" @click="handleNextTab">下一步</el-button>
|
||||||
<template #footer>
|
<el-button v-else-if="activeTab === 'sku'" type="primary" @click="handleNextTab">下一步</el-button>
|
||||||
<el-button v-if="activeTab === 'sku'" @click="activeTab = 'base'">上一步</el-button>
|
<el-button v-else-if="activeTab === 'merchant'" type="primary" @click="onSubmit" :disabled="loading">完成</el-button>
|
||||||
<el-button v-if="activeTab === 'merchant'" @click="activeTab = 'sku'">上一步</el-button>
|
<el-button @click="visible = false">取消</el-button>
|
||||||
<el-button v-if="activeTab === 'base'" type="primary" @click="handleNextTab">下一步</el-button>
|
</template>
|
||||||
<el-button v-else-if="activeTab === 'sku'" type="primary" @click="handleNextTab">下一步</el-button>
|
</el-dialog>
|
||||||
<el-button v-else-if="activeTab === 'merchant'" type="primary" @click="onSubmit" :disabled="loading">完成</el-button>
|
|
||||||
<el-button @click="visible = false">取消</el-button>
|
|
||||||
</template>
|
|
||||||
</el-dialog>
|
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts" name="ShopSpuDialog">
|
<script setup lang="ts" name="ShopSpuDialog">
|
||||||
import { useDict } from '/@/hooks/dict';
|
import { useDict } from "/@/hooks/dict"
|
||||||
import { useMessage } from "/@/hooks/message";
|
import { useMessage } from "/@/hooks/message"
|
||||||
import { getObj, addObj, putObj } from '/@/api/supermarket/shopSpu';
|
import { getObj, addObj, putObj } from "/@/api/supermarket/shopSpu"
|
||||||
import { rule } from '/@/utils/validate';
|
import { rule } from "/@/utils/validate"
|
||||||
import { tree as fetchCategoryTree } from '/@/api/supermarket/shopCategory';
|
import { tree as fetchCategoryTree } from "/@/api/supermarket/shopCategory"
|
||||||
import { select as fetchMerchantSelect } from '/@/api/wallet/mch-manage';
|
import { select as fetchMerchantSelect } from "/@/api/wallet/mch-manage"
|
||||||
|
import { displayPrice, storePrice } from "/@/utils/formatMoney"
|
||||||
|
|
||||||
const emit = defineEmits(['refresh']);
|
const emit = defineEmits(["refresh"])
|
||||||
|
|
||||||
// 定义变量内容
|
// 定义变量内容
|
||||||
const dataFormRef = ref();
|
const dataFormRef = ref()
|
||||||
const visible = ref(false)
|
const visible = ref(false)
|
||||||
const loading = ref(false)
|
const loading = ref(false)
|
||||||
// 定义字典
|
// 定义字典
|
||||||
const { supermarket_nature,spu_status} = useDict("supermarket_nature",'spu_status')
|
const { supermarket_nature, status } = useDict("supermarket_nature", "status")
|
||||||
// 提交表单数据
|
// 提交表单数据
|
||||||
const form = reactive({
|
const form = reactive({
|
||||||
id: '',
|
id: "",
|
||||||
productCode: '',
|
productCode: "",
|
||||||
productName: '',
|
productName: "",
|
||||||
productNature: "",
|
productNature: "",
|
||||||
description: '',
|
description: "",
|
||||||
categoryId: '',
|
categoryId: "",
|
||||||
picUrl: '',
|
picUrl: "",
|
||||||
sliderPicUrls: '',
|
sliderPicUrls: "",
|
||||||
sort: 0,
|
sort: 0,
|
||||||
status: '',
|
status: "0",
|
||||||
stock: 0,
|
stock: 0,
|
||||||
giveIntegral: '',
|
giveIntegral: "",
|
||||||
merchantRelationId: '',
|
merchantRelationId: "",
|
||||||
deptId: '',
|
deptId: "",
|
||||||
shopSkuId: '',
|
shopSkuId: "",
|
||||||
salesCount: '',
|
salesCount: "",
|
||||||
limitNum: 0,
|
limitNum: 0,
|
||||||
skuList: [] as any[],
|
skuList: [] as any[],
|
||||||
});
|
})
|
||||||
|
|
||||||
// 定义校验规则
|
// 定义校验规则
|
||||||
const dataRules = ref({
|
const dataRules = ref({
|
||||||
productNature: [{ required: true, message: "请选择商品性质", trigger: "blur" }],
|
productNature: [{ required: true, message: "请选择商品性质", trigger: "blur" }],
|
||||||
productCode: [{ required: true, message: '货号不能为空', trigger: 'blur' }],
|
productCode: [{ required: true, message: "货号不能为空", trigger: "blur" }],
|
||||||
productName: [{ required: true, message: '商品名称不能为空', trigger: 'blur' }],
|
productName: [{ required: true, message: "商品名称不能为空", trigger: "blur" }],
|
||||||
categoryId: [{ required: true, message: '商品分类不能为空', trigger: 'change' }],
|
categoryId: [{ required: true, message: "商品分类不能为空", trigger: "change" }],
|
||||||
picUrl: [{ required: true, message: '商品封面图不能为空', trigger: 'change' }],
|
picUrl: [{ required: true, message: "商品封面图不能为空", trigger: "change" }],
|
||||||
sort: [{validator: rule.number, trigger: 'blur'}],
|
sort: [{ validator: rule.number, trigger: "blur" }],
|
||||||
stock: [{validator: rule.number, trigger: 'blur'}],
|
stock: [{ validator: rule.number, trigger: "blur" }],
|
||||||
limitNum: [{validator: rule.number, trigger: 'blur'}],
|
limitNum: [{ validator: rule.number, trigger: "blur" }],
|
||||||
})
|
})
|
||||||
|
|
||||||
const categoryOptions = ref<any[]>([]);
|
const categoryOptions = ref<any[]>([])
|
||||||
|
|
||||||
const loadCategoryTree = async () => {
|
const loadCategoryTree = async () => {
|
||||||
const res = await fetchCategoryTree();
|
const res = await fetchCategoryTree()
|
||||||
categoryOptions.value = res.data || [];
|
categoryOptions.value = res.data || []
|
||||||
};
|
}
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
loadCategoryTree();
|
loadCategoryTree()
|
||||||
});
|
})
|
||||||
|
|
||||||
const activeTab = ref('base');
|
const activeTab = ref("base")
|
||||||
|
|
||||||
// 打开弹窗
|
// 打开弹窗
|
||||||
const openDialog = (id: string) => {
|
const openDialog = (id: string) => {
|
||||||
visible.value = true
|
visible.value = true
|
||||||
activeTab.value = 'base';
|
activeTab.value = "base"
|
||||||
if (!id) {
|
if (!id) {
|
||||||
// 新增时彻底重置所有表单数据
|
// 新增时彻底重置所有表单数据
|
||||||
Object.assign(form, {
|
Object.assign(form, {
|
||||||
id: '',
|
id: "",
|
||||||
productCode: '',
|
productCode: "",
|
||||||
productName: '',
|
productName: "",
|
||||||
description: '',
|
description: "",
|
||||||
categoryId: '',
|
categoryId: "",
|
||||||
picUrl: '',
|
picUrl: "",
|
||||||
sliderPicUrls: '',
|
sliderPicUrls: "",
|
||||||
sort: 0,
|
sort: 0,
|
||||||
status: '',
|
status: "",
|
||||||
stock: 0,
|
stock: 0,
|
||||||
giveIntegral: '',
|
giveIntegral: "",
|
||||||
merchantRelationId: '',
|
merchantRelationId: "",
|
||||||
deptId: '',
|
deptId: "",
|
||||||
shopSkuId: '',
|
shopSkuId: "",
|
||||||
salesCount: '',
|
salesCount: "",
|
||||||
limitNum: 0,
|
limitNum: 0,
|
||||||
skuList: []
|
skuList: [],
|
||||||
});
|
})
|
||||||
selectedMerchants.value = [];
|
selectedMerchants.value = []
|
||||||
selectedMerchantIds.value = [];
|
selectedMerchantIds.value = []
|
||||||
// skuList至少有一条
|
// skuList至少有一条
|
||||||
addSku();
|
addSku()
|
||||||
nextTick(() => {
|
nextTick(() => {
|
||||||
dataFormRef.value?.resetFields();
|
dataFormRef.value?.resetFields()
|
||||||
});
|
})
|
||||||
} else {
|
} else {
|
||||||
form.id = id;
|
form.id = id
|
||||||
nextTick(() => {
|
nextTick(() => {
|
||||||
dataFormRef.value?.resetFields();
|
dataFormRef.value?.resetFields()
|
||||||
});
|
})
|
||||||
getshopSpuData(id);
|
getshopSpuData(id)
|
||||||
}
|
}
|
||||||
// 重新加载分类树
|
// 重新加载分类树
|
||||||
loadCategoryTree();
|
loadCategoryTree()
|
||||||
};
|
}
|
||||||
|
|
||||||
// 提交
|
// 提交
|
||||||
const onSubmit = async () => {
|
const onSubmit = async () => {
|
||||||
const valid = await dataFormRef.value.validate().catch(() => {});
|
const valid = await dataFormRef.value.validate().catch(() => {})
|
||||||
if (!valid) return false;
|
if (!valid) return false
|
||||||
if (!selectedMerchants.value.length) {
|
if (!selectedMerchants.value.length) {
|
||||||
useMessage().error('请至少选择一个在销商户');
|
useMessage().error("请至少选择一个在销商户")
|
||||||
activeTab.value = 'merchant';
|
activeTab.value = "merchant"
|
||||||
return false;
|
return false
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
loading.value = true;
|
loading.value = true
|
||||||
// merchantIds 逗号分隔字符串
|
// merchantIds 逗号分隔字符串
|
||||||
const merchantIds = selectedMerchants.value.map(m => m.id).join(',');
|
const merchantIds = selectedMerchants.value.map((m) => m.id).join(",")
|
||||||
const submitForm = {
|
const submitForm = {
|
||||||
...form,
|
...form,
|
||||||
categoryId: Array.isArray(form.categoryId) ? form.categoryId.slice(-1)[0] : form.categoryId,
|
categoryId: Array.isArray(form.categoryId) ? form.categoryId.slice(-1)[0] : form.categoryId,
|
||||||
merchantIds
|
merchantIds,
|
||||||
};
|
skuList:
|
||||||
form.id ? await putObj(submitForm) : await addObj(submitForm);
|
form.skuList?.map((sku) => {
|
||||||
useMessage().success(form.id ? '修改成功' : '添加成功');
|
return {
|
||||||
visible.value = false;
|
...sku,
|
||||||
emit('refresh');
|
promotionPrice: storePrice(sku.promotionPrice),
|
||||||
} catch (err: any) {
|
retailPrice: storePrice(sku.retailPrice),
|
||||||
useMessage().error(err.msg);
|
}
|
||||||
} finally {
|
}) || [],
|
||||||
loading.value = false;
|
}
|
||||||
}
|
form.id ? await putObj(submitForm) : await addObj(submitForm)
|
||||||
};
|
useMessage().success(form.id ? "修改成功" : "添加成功")
|
||||||
|
visible.value = false
|
||||||
|
emit("refresh")
|
||||||
|
} catch (err: any) {
|
||||||
|
useMessage().error(err.msg)
|
||||||
|
} finally {
|
||||||
|
loading.value = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// 初始化表单数据
|
// 初始化表单数据
|
||||||
const getshopSpuData = (id: string) => {
|
const getshopSpuData = (id: string) => {
|
||||||
// 获取数据
|
// 获取数据
|
||||||
loading.value = true
|
loading.value = true
|
||||||
getObj(id).then((res: any) => {
|
getObj(id)
|
||||||
Object.assign(form, res.data)
|
.then((res: any) => {
|
||||||
form.skuList = res.data.skuList || []
|
Object.assign(form, res.data)
|
||||||
// skuList至少有一条
|
form.skuList =
|
||||||
if (!form.skuList || form.skuList.length === 0) {
|
res.data.skuList.map((item: any) => {
|
||||||
addSku();
|
return { ...item, promotionPrice: displayPrice(item.promotionPrice, ""), retailPrice: displayPrice(item.retailPrice, "") }
|
||||||
}
|
}) || []
|
||||||
// 处理 categoryId 回显为数组
|
// skuList至少有一条
|
||||||
if (res.data.categoryId && categoryOptions.value.length) {
|
if (!form.skuList || form.skuList.length === 0) {
|
||||||
form.categoryId = findCategoryPath(categoryOptions.value, res.data.categoryId);
|
addSku()
|
||||||
}
|
}
|
||||||
// 处理 merchantIds 回显
|
// 处理 categoryId 回显为数组
|
||||||
if (res.data.merchantIds) {
|
if (res.data.categoryId && categoryOptions.value.length) {
|
||||||
const idsArr = typeof res.data.merchantIds === 'string' ? res.data.merchantIds.split(',').filter(Boolean) : [];
|
form.categoryId = findCategoryPath(categoryOptions.value, res.data.categoryId)
|
||||||
selectedMerchantIds.value = idsArr;
|
}
|
||||||
if (merchantList.value.length) {
|
// 处理 merchantIds 回显
|
||||||
selectedMerchants.value = merchantList.value.filter(m => idsArr.includes(String(m.id)));
|
if (res.data.merchantIds) {
|
||||||
} else {
|
const idsArr = typeof res.data.merchantIds === "string" ? res.data.merchantIds.split(",").filter(Boolean) : []
|
||||||
fetchMerchantList().then(() => {
|
selectedMerchantIds.value = idsArr
|
||||||
selectedMerchants.value = merchantList.value.filter(m => idsArr.includes(String(m.id)));
|
if (merchantList.value.length) {
|
||||||
});
|
selectedMerchants.value = merchantList.value.filter((m) => idsArr.includes(String(m.id)))
|
||||||
}
|
} else {
|
||||||
} else {
|
fetchMerchantList().then(() => {
|
||||||
selectedMerchants.value = [];
|
selectedMerchants.value = merchantList.value.filter((m) => idsArr.includes(String(m.id)))
|
||||||
selectedMerchantIds.value = [];
|
})
|
||||||
}
|
}
|
||||||
}).finally(() => {
|
} else {
|
||||||
loading.value = false
|
selectedMerchants.value = []
|
||||||
})
|
selectedMerchantIds.value = []
|
||||||
};
|
}
|
||||||
|
})
|
||||||
|
.finally(() => {
|
||||||
|
loading.value = false
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
function addSku() {
|
function addSku() {
|
||||||
form.skuList.push({
|
form.skuList.push({
|
||||||
barCode: '',
|
barCode: "",
|
||||||
spec: '',
|
spec: "",
|
||||||
unit: '',
|
unit: "",
|
||||||
status: 0,
|
status: 0,
|
||||||
promotionPrice: 0,
|
promotionPrice: 0,
|
||||||
stock: '',
|
stock: "",
|
||||||
attribute: ''
|
attribute: "",
|
||||||
});
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
function removeSku(index: number) {
|
function removeSku(index: number) {
|
||||||
form.skuList.splice(index, 1);
|
form.skuList.splice(index, 1)
|
||||||
}
|
}
|
||||||
|
|
||||||
// 分步校验tab切换
|
// 分步校验tab切换
|
||||||
const handleTabLeave = async (newTab: string, oldTab: string) => {
|
const handleTabLeave = async (newTab: string, oldTab: string) => {
|
||||||
// 基本信息tab校验
|
// 基本信息tab校验
|
||||||
if (oldTab === 'base' && newTab !== 'base') {
|
if (oldTab === "base" && newTab !== "base") {
|
||||||
// 校验基本信息必填
|
// 校验基本信息必填
|
||||||
const valid = await dataFormRef.value.validateField([
|
const valid = await dataFormRef.value.validateField(["productCode", "productName", "categoryId", "picUrl"]).catch(() => false)
|
||||||
'productCode', 'productName', 'categoryId', 'picUrl'
|
return !!valid
|
||||||
]).catch(() => false);
|
}
|
||||||
return !!valid;
|
// SKU信息tab校验
|
||||||
}
|
if (oldTab === "sku" && newTab === "merchant") {
|
||||||
// SKU信息tab校验
|
// 校验SKU表格必填
|
||||||
if (oldTab === 'sku' && newTab === 'merchant') {
|
let valid = true
|
||||||
// 校验SKU表格必填
|
for (let i = 0; i < form.skuList.length; i++) {
|
||||||
let valid = true;
|
const sku = form.skuList[i]
|
||||||
for (let i = 0; i < form.skuList.length; i++) {
|
if (!sku.barCode || !sku.unit || !sku.retailPrice || !sku.stock) {
|
||||||
const sku = form.skuList[i];
|
useMessage().error(`第${i + 1}行SKU必填项未填写`)
|
||||||
if (!sku.barCode || !sku.unit || !sku.retailPrice || !sku.stock) {
|
valid = false
|
||||||
useMessage().error(`第${i + 1}行SKU必填项未填写`);
|
break
|
||||||
valid = false;
|
}
|
||||||
break;
|
}
|
||||||
}
|
return valid
|
||||||
}
|
}
|
||||||
return valid;
|
return true
|
||||||
}
|
}
|
||||||
return true;
|
|
||||||
};
|
|
||||||
|
|
||||||
const tabOrder = ['base', 'sku', 'merchant'];
|
const tabOrder = ["base", "sku", "merchant"]
|
||||||
function handleNextTab() {
|
function handleNextTab() {
|
||||||
if (activeTab.value === 'base') {
|
if (activeTab.value === "base") {
|
||||||
dataFormRef.value.validateField(['productCode', 'productName', 'categoryId', 'picUrl']).then(() => {
|
dataFormRef.value.validateField(["productCode", "productName", "categoryId", "picUrl"]).then(() => {
|
||||||
activeTab.value = 'sku';
|
activeTab.value = "sku"
|
||||||
});
|
})
|
||||||
} else if (activeTab.value === 'sku') {
|
} else if (activeTab.value === "sku") {
|
||||||
// 校验SKU表格必填
|
// 校验SKU表格必填
|
||||||
let valid = true;
|
let valid = true
|
||||||
for (let i = 0; i < form.skuList.length; i++) {
|
for (let i = 0; i < form.skuList.length; i++) {
|
||||||
const sku = form.skuList[i];
|
const sku = form.skuList[i]
|
||||||
if (!sku.barCode || !sku.unit || !sku.retailPrice || !sku.stock) {
|
if (!sku.barCode || !sku.unit || !sku.retailPrice || !sku.stock) {
|
||||||
useMessage().error(`第${i + 1}行SKU必填项未填写`);
|
useMessage().error(`第${i + 1}行SKU必填项未填写`)
|
||||||
valid = false;
|
valid = false
|
||||||
break;
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (valid) {
|
if (valid) {
|
||||||
activeTab.value = 'merchant';
|
activeTab.value = "merchant"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function requiredLabel(label: string) {
|
function requiredLabel(label: string) {
|
||||||
return `<span class='required'>*</span> ${label}`;
|
return `<span class='required'>*</span> ${label}`
|
||||||
}
|
}
|
||||||
const tableHeaderStyle = () => ({ 'font-weight': 'bold' });
|
const tableHeaderStyle = () => ({ "font-weight": "bold" })
|
||||||
|
|
||||||
// 暴露变量
|
// 暴露变量
|
||||||
defineExpose({
|
defineExpose({
|
||||||
openDialog
|
openDialog,
|
||||||
});
|
})
|
||||||
|
|
||||||
const showMerchantDialog = ref(false);
|
const showMerchantDialog = ref(false)
|
||||||
const merchantList = ref<any[]>([]);
|
const merchantList = ref<any[]>([])
|
||||||
const merchantSearch = ref('');
|
const merchantSearch = ref("")
|
||||||
const selectedMerchants = ref<any[]>([]);
|
const selectedMerchants = ref<any[]>([])
|
||||||
const selectedMerchantIds = ref<any[]>([]);
|
const selectedMerchantIds = ref<any[]>([])
|
||||||
|
|
||||||
const fetchMerchantList = async () => {
|
const fetchMerchantList = async () => {
|
||||||
const res = await fetchMerchantSelect({
|
const res = await fetchMerchantSelect({
|
||||||
name: merchantSearch.value,
|
name: merchantSearch.value,
|
||||||
current: 1,
|
current: 1,
|
||||||
size: 9999,
|
size: 9999,
|
||||||
types: 3
|
types: 3,
|
||||||
});
|
})
|
||||||
merchantList.value = res.data?.records || [];
|
merchantList.value = res.data?.records || []
|
||||||
};
|
}
|
||||||
|
|
||||||
const handleMerchantSelect = (rows: any[]) => {
|
const handleMerchantSelect = (rows: any[]) => {
|
||||||
selectedMerchantIds.value = rows.map((row: any) => (row as any).id);
|
selectedMerchantIds.value = rows.map((row: any) => (row as any).id)
|
||||||
};
|
}
|
||||||
|
|
||||||
const confirmMerchantSelect = () => {
|
const confirmMerchantSelect = () => {
|
||||||
selectedMerchants.value = merchantList.value.filter(m => selectedMerchantIds.value.includes(m.id));
|
selectedMerchants.value = merchantList.value.filter((m) => selectedMerchantIds.value.includes(m.id))
|
||||||
showMerchantDialog.value = false;
|
showMerchantDialog.value = false
|
||||||
};
|
}
|
||||||
|
|
||||||
const removeMerchant = (idx: number) => {
|
const removeMerchant = (idx: number) => {
|
||||||
selectedMerchants.value.splice(idx, 1);
|
selectedMerchants.value.splice(idx, 1)
|
||||||
selectedMerchantIds.value = selectedMerchants.value.map(m => m.id);
|
selectedMerchantIds.value = selectedMerchants.value.map((m) => m.id)
|
||||||
};
|
}
|
||||||
|
|
||||||
// 打开弹窗时自动加载商户
|
// 打开弹窗时自动加载商户
|
||||||
watch(showMerchantDialog, (val) => { if (val) fetchMerchantList(); });
|
watch(showMerchantDialog, (val) => {
|
||||||
|
if (val) fetchMerchantList()
|
||||||
|
})
|
||||||
|
|
||||||
// 工具函数:根据分类id查找路径
|
// 工具函数:根据分类id查找路径
|
||||||
function findCategoryPath(options, targetId, path = []) {
|
function findCategoryPath(options, targetId, path = []) {
|
||||||
for (const item of options) {
|
for (const item of options) {
|
||||||
const newPath = path.concat(item.id);
|
const newPath = path.concat(item.id)
|
||||||
if (item.id === targetId) return newPath;
|
if (item.id === targetId) return newPath
|
||||||
if (item.children) {
|
if (item.children) {
|
||||||
const childPath = findCategoryPath(item.children, targetId, newPath);
|
const childPath = findCategoryPath(item.children, targetId, newPath)
|
||||||
if (childPath.length) return childPath;
|
if (childPath.length) return childPath
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return [];
|
return []
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped>
|
<style scoped>
|
||||||
.required {
|
.required {
|
||||||
color: #f56c6c;
|
color: #f56c6c;
|
||||||
margin-right: 2px;
|
margin-right: 2px;
|
||||||
}
|
}
|
||||||
.el-table .el-form-item {
|
.el-table .el-form-item {
|
||||||
margin-bottom: 0;
|
margin-bottom: 0;
|
||||||
}
|
}
|
||||||
.el-table .el-form-item__error {
|
.el-table .el-form-item__error {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
top: 100%;
|
top: 100%;
|
||||||
left: 0;
|
left: 0;
|
||||||
font-size: 12px;
|
font-size: 12px;
|
||||||
color: #f56c6c;
|
color: #f56c6c;
|
||||||
line-height: 1.2;
|
line-height: 1.2;
|
||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
}
|
}
|
||||||
.el-table .el-table__cell {
|
.el-table .el-table__cell {
|
||||||
vertical-align: top;
|
vertical-align: top;
|
||||||
position: relative;
|
position: relative;
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
@@ -1,87 +1,111 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="layout-padding">
|
<div class="layout-padding">
|
||||||
<div class="layout-padding-auto layout-padding-view">
|
<div class="layout-padding-auto layout-padding-view">
|
||||||
<el-row v-show="showSearch">
|
<el-row v-show="showSearch">
|
||||||
<el-form :model="state.queryForm" ref="queryRef" :inline="true" @keyup.enter="getDataList">
|
<el-form :model="state.queryForm" ref="queryRef" :inline="true" @keyup.enter="getDataList">
|
||||||
<el-form-item label="商品名称" prop="productName" >
|
<el-form-item label="商品名称" prop="productName">
|
||||||
<el-input placeholder="请输入商品名称" v-model="state.queryForm.productName" />
|
<el-input placeholder="请输入商品名称" v-model="state.queryForm.productName" />
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item>
|
<el-form-item>
|
||||||
<el-button icon="search" type="primary" @click="getDataList">
|
<el-button icon="search" type="primary" @click="getDataList"> 查询 </el-button>
|
||||||
查询
|
<el-button icon="Refresh" @click="resetQuery">重置</el-button>
|
||||||
</el-button>
|
</el-form-item>
|
||||||
<el-button icon="Refresh" @click="resetQuery">重置</el-button>
|
</el-form>
|
||||||
</el-form-item>
|
</el-row>
|
||||||
</el-form>
|
<el-row>
|
||||||
</el-row>
|
<div class="mb8" style="width: 100%">
|
||||||
<el-row>
|
<el-button icon="folder-add" type="primary" class="ml10" @click="formDialogRef.openDialog()" v-auth="'supermarket_shopSpu_add'">
|
||||||
<div class="mb8" style="width: 100%">
|
新 增
|
||||||
<el-button icon="folder-add" type="primary" class="ml10" @click="formDialogRef.openDialog()"
|
</el-button>
|
||||||
v-auth="'supermarket_shopSpu_add'">
|
<el-button
|
||||||
新 增
|
plain
|
||||||
</el-button>
|
:disabled="multiple"
|
||||||
<el-button plain :disabled="multiple" icon="Delete" type="primary"
|
icon="Delete"
|
||||||
v-auth="'supermarket_shopSpu_del'" @click="handleDelete(selectObjs)">
|
type="primary"
|
||||||
删除
|
v-auth="'supermarket_shopSpu_del'"
|
||||||
</el-button>
|
@click="handleDelete(selectObjs)"
|
||||||
<right-toolbar v-model:showSearch="showSearch" :export="'supermarket_shopSpu_export'"
|
>
|
||||||
@exportExcel="exportExcel" class="ml10 mr20" style="float: right;"
|
删除
|
||||||
@queryTable="getDataList"></right-toolbar>
|
</el-button>
|
||||||
</div>
|
<right-toolbar
|
||||||
</el-row>
|
v-model:showSearch="showSearch"
|
||||||
<el-table :data="state.dataList" v-loading="state.loading" border
|
:export="'supermarket_shopSpu_export'"
|
||||||
:cell-style="tableStyle.cellStyle" :header-cell-style="tableStyle.headerCellStyle"
|
@exportExcel="exportExcel"
|
||||||
|
class="ml10 mr20"
|
||||||
|
style="float: right"
|
||||||
|
@queryTable="getDataList"
|
||||||
|
></right-toolbar>
|
||||||
|
</div>
|
||||||
|
</el-row>
|
||||||
|
<el-table
|
||||||
|
:data="state.dataList"
|
||||||
|
v-loading="state.loading"
|
||||||
|
border
|
||||||
|
:cell-style="tableStyle.cellStyle"
|
||||||
|
:header-cell-style="tableStyle.headerCellStyle"
|
||||||
@selection-change="selectionChangHandle"
|
@selection-change="selectionChangHandle"
|
||||||
@sort-change="sortChangeHandle">
|
@sort-change="sortChangeHandle"
|
||||||
<el-table-column type="selection" width="40" align="center" />
|
>
|
||||||
<el-table-column type="index" label="#" width="40" />
|
<el-table-column type="selection" width="40" align="center" />
|
||||||
<el-table-column prop="productCode" label="货号" show-overflow-tooltip/>
|
<el-table-column type="index" label="#" width="40" />
|
||||||
<el-table-column prop="productName" label="商品名称" show-overflow-tooltip/>
|
<el-table-column prop="productCode" label="货号" show-overflow-tooltip />
|
||||||
<el-table-column prop="categoryId" label="商品分类" show-overflow-tooltip>
|
<el-table-column prop="productName" label="商品名称" show-overflow-tooltip />
|
||||||
<template #default="scope">
|
<el-table-column prop="categoryId" label="商品分类" show-overflow-tooltip>
|
||||||
{{ findCategoryPath(categoryOptions, scope.row.categoryId).join(' / ') }}
|
<template #default="scope">
|
||||||
</template>
|
{{ findCategoryPath(categoryOptions, scope.row.categoryId).join(" / ") }}
|
||||||
</el-table-column>
|
</template>
|
||||||
<el-table-column prop="picUrl" label="商品封面图" show-overflow-tooltip/>
|
</el-table-column>
|
||||||
<el-table-column prop="sort" label="排序字段" show-overflow-tooltip/>
|
<el-table-column prop="picUrl" label="商品封面图" show-overflow-tooltip>
|
||||||
<el-table-column prop="status" label="商品状态" show-overflow-tooltip>
|
<template #default="scope">
|
||||||
<template #default="scope">
|
<preview-image :src="scope.row.picUrl" />
|
||||||
<dict-tag :options="spu_status" :value="scope.row.status"></dict-tag>
|
</template>
|
||||||
</template>
|
</el-table-column>
|
||||||
</el-table-column>
|
<el-table-column prop="sort" label="排序" show-overflow-tooltip />
|
||||||
<el-table-column prop="stock" label="库存" show-overflow-tooltip/>
|
<el-table-column prop="status" label="商品状态" show-overflow-tooltip>
|
||||||
<el-table-column prop="salesCount" label="销量" show-overflow-tooltip/>
|
<template #default="scope">
|
||||||
<el-table-column prop="limitNum" label="单人限购数" show-overflow-tooltip/>
|
<dict-tag :options="spu_status" :value="scope.row.status"></dict-tag>
|
||||||
<el-table-column label="操作" width="150">
|
</template>
|
||||||
<template #default="scope">
|
</el-table-column>
|
||||||
<el-button icon="edit-pen" text type="primary" v-auth="'supermarket_shopSpu_edit'"
|
<el-table-column prop="stock" label="库存" show-overflow-tooltip />
|
||||||
@click="formDialogRef.openDialog(scope.row.id)">编辑</el-button>
|
<el-table-column prop="salesCount" label="销量" show-overflow-tooltip />
|
||||||
<el-button icon="delete" text type="primary" v-auth="'supermarket_shopSpu_del'" @click="handleDelete([scope.row.id])">删除</el-button>
|
<el-table-column prop="limitNum" label="单人限购数" show-overflow-tooltip />
|
||||||
</template>
|
<el-table-column label="操作" width="150">
|
||||||
</el-table-column>
|
<template #default="scope">
|
||||||
</el-table>
|
<el-button
|
||||||
<pagination @size-change="sizeChangeHandle" @current-change="currentChangeHandle" v-bind="state.pagination" />
|
icon="edit-pen"
|
||||||
</div>
|
text
|
||||||
|
type="primary"
|
||||||
|
v-auth="'supermarket_shopSpu_edit'"
|
||||||
|
@click="formDialogRef.openDialog(scope.row.id)"
|
||||||
|
>编辑</el-button
|
||||||
|
>
|
||||||
|
<el-button icon="delete" text type="primary" v-auth="'supermarket_shopSpu_del'" @click="handleDelete([scope.row.id])"
|
||||||
|
>删除</el-button
|
||||||
|
>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
</el-table>
|
||||||
|
<pagination @size-change="sizeChangeHandle" @current-change="currentChangeHandle" v-bind="state.pagination" />
|
||||||
|
</div>
|
||||||
|
|
||||||
<!-- 编辑、新增 -->
|
<!-- 编辑、新增 -->
|
||||||
<form-dialog ref="formDialogRef" @refresh="getDataList(false)" />
|
<form-dialog ref="formDialogRef" @refresh="getDataList(false)" />
|
||||||
|
</div>
|
||||||
</div>
|
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts" name="systemShopSpu">
|
<script setup lang="ts" name="systemShopSpu">
|
||||||
import { BasicTableProps, useTable } from "/src/hooks/table";
|
import { BasicTableProps, useTable } from "/src/hooks/table"
|
||||||
import { fetchList, delObjs, putObj } from "/src/api/supermarket/shopSpu";
|
import { fetchList, delObjs, putObj } from "/src/api/supermarket/shopSpu"
|
||||||
import { useMessage, useMessageBox } from "/src/hooks/message";
|
import { useMessage, useMessageBox } from "/src/hooks/message"
|
||||||
import { useDict } from '/src/hooks/dict';
|
import { useDict } from "/src/hooks/dict"
|
||||||
import { tree as fetchCategoryTree } from '/src/api/supermarket/shopCategory';
|
import { tree as fetchCategoryTree } from "/src/api/supermarket/shopCategory"
|
||||||
import { onMounted, ref } from 'vue';
|
import { onMounted, ref } from "vue"
|
||||||
|
|
||||||
// 引入组件
|
// 引入组件
|
||||||
const FormDialog = defineAsyncComponent(() => import('./form.vue'));
|
const FormDialog = defineAsyncComponent(() => import("./form.vue"))
|
||||||
// 定义查询字典
|
// 定义查询字典
|
||||||
|
|
||||||
const { spu_status } = useDict('spu_status')
|
const { spu_status } = useDict("spu_status")
|
||||||
// 定义变量内容
|
// 定义变量内容
|
||||||
const formDialogRef = ref()
|
const formDialogRef = ref()
|
||||||
// 搜索变量
|
// 搜索变量
|
||||||
@@ -92,74 +116,67 @@ const selectObjs = ref([]) as any
|
|||||||
const multiple = ref(true)
|
const multiple = ref(true)
|
||||||
|
|
||||||
const state: BasicTableProps = reactive<BasicTableProps>({
|
const state: BasicTableProps = reactive<BasicTableProps>({
|
||||||
queryForm: {},
|
queryForm: {},
|
||||||
pageList: fetchList
|
pageList: fetchList,
|
||||||
})
|
})
|
||||||
|
|
||||||
// table hook
|
// table hook
|
||||||
const {
|
const { getDataList, currentChangeHandle, sizeChangeHandle, sortChangeHandle, downBlobFile, tableStyle } = useTable(state)
|
||||||
getDataList,
|
|
||||||
currentChangeHandle,
|
|
||||||
sizeChangeHandle,
|
|
||||||
sortChangeHandle,
|
|
||||||
downBlobFile,
|
|
||||||
tableStyle
|
|
||||||
} = useTable(state)
|
|
||||||
|
|
||||||
// 分类树数据
|
// 分类树数据
|
||||||
const categoryOptions = ref<any[]>([]);
|
const categoryOptions = ref<any[]>([])
|
||||||
onMounted(async () => {
|
onMounted(async () => {
|
||||||
const res = await fetchCategoryTree();
|
const res = await fetchCategoryTree()
|
||||||
categoryOptions.value = res.data || [];
|
categoryOptions.value = res.data || []
|
||||||
});
|
})
|
||||||
|
|
||||||
// 递归查找分类路径
|
// 递归查找分类路径
|
||||||
function findCategoryPath(options: any[], id: string | number, path: string[] = []): string[] {
|
function findCategoryPath(options: any[], id: string | number, path: string[] = []): string[] {
|
||||||
for (const item of options) {
|
for (const item of options) {
|
||||||
const newPath = [...path, item.name];
|
const newPath = [...path, item.name]
|
||||||
if (item.id == id) return newPath;
|
if (item.id == id) return newPath
|
||||||
if (item.children) {
|
if (item.children) {
|
||||||
const result = findCategoryPath(item.children, id, newPath);
|
const result = findCategoryPath(item.children, id, newPath)
|
||||||
if (result.length) return result;
|
if (result.length) return result
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return [];
|
return []
|
||||||
}
|
}
|
||||||
|
|
||||||
// 清空搜索条件
|
// 清空搜索条件
|
||||||
const resetQuery = () => {
|
const resetQuery = () => {
|
||||||
// 清空搜索条件
|
// 清空搜索条件
|
||||||
queryRef.value?.resetFields()
|
queryRef.value?.resetFields()
|
||||||
// 清空多选
|
// 清空多选
|
||||||
selectObjs.value = []
|
selectObjs.value = []
|
||||||
getDataList()
|
getDataList()
|
||||||
}
|
}
|
||||||
|
|
||||||
// 导出excel
|
// 导出excel
|
||||||
const exportExcel = () => {
|
const exportExcel = () => {
|
||||||
downBlobFile('/supermarket/shopSpu/export', Object.assign(state.queryForm, { ids: selectObjs }), 'shopSpu.xlsx')
|
downBlobFile("/supermarket/shopSpu/export", Object.assign(state.queryForm, { ids: selectObjs }), "shopSpu.xlsx")
|
||||||
}
|
}
|
||||||
|
|
||||||
// 多选事件
|
// 多选事件
|
||||||
const selectionChangHandle = (objs: { id: string }[]) => {
|
const selectionChangHandle = (objs: { id: string }[]) => {
|
||||||
selectObjs.value = objs.map(({ id }) => id);
|
selectObjs.value = objs.map(({ id }) => id)
|
||||||
multiple.value = !objs.length;
|
multiple.value = !objs.length
|
||||||
};
|
}
|
||||||
|
|
||||||
// 删除操作
|
// 删除操作
|
||||||
const handleDelete = async (ids: string[]) => {
|
const handleDelete = async (ids: string[]) => {
|
||||||
try {
|
try {
|
||||||
await useMessageBox().confirm('此操作将永久删除');
|
await useMessageBox().confirm("此操作将永久删除")
|
||||||
} catch {
|
} catch {
|
||||||
return;
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
await delObjs(ids);
|
await delObjs(ids)
|
||||||
getDataList();
|
getDataList()
|
||||||
useMessage().success('删除成功');
|
useMessage().success("删除成功")
|
||||||
} catch (err: any) {
|
} catch (err: any) {
|
||||||
useMessage().error(err.msg);
|
useMessage().error(err.msg)
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
</script>
|
</script>
|
||||||
@@ -129,6 +129,11 @@
|
|||||||
<el-input-number v-else v-model="row.quantity" :min="0" :precision="2" @change="onRowValueChange(row, $rowIndex)" />
|
<el-input-number v-else v-model="row.quantity" :min="0" :precision="2" @change="onRowValueChange(row, $rowIndex)" />
|
||||||
</template>
|
</template>
|
||||||
</vxe-column>
|
</vxe-column>
|
||||||
|
<vxe-column field="purchasePrice" title="零售价">
|
||||||
|
<template #default="{ row }">
|
||||||
|
{{ displayPrice(row.selectedUnitObj?.retailPrice || 0) }}
|
||||||
|
</template>
|
||||||
|
</vxe-column>
|
||||||
<vxe-column field="purchasePrice" title="原进价">
|
<vxe-column field="purchasePrice" title="原进价">
|
||||||
<template #default="{ row }">
|
<template #default="{ row }">
|
||||||
{{ displayPrice(row.selectedUnitObj?.purchasePrice || 0) }}
|
{{ displayPrice(row.selectedUnitObj?.purchasePrice || 0) }}
|
||||||
|
|||||||
@@ -157,6 +157,11 @@
|
|||||||
<el-input-number v-else v-model="row.quantity" :min="0" :precision="2" @change="onQuantityChange(row, $rowIndex)" />
|
<el-input-number v-else v-model="row.quantity" :min="0" :precision="2" @change="onQuantityChange(row, $rowIndex)" />
|
||||||
</template>
|
</template>
|
||||||
</vxe-column>
|
</vxe-column>
|
||||||
|
<vxe-column field="purchasePrice" title="零售价">
|
||||||
|
<template #default="{ row }">
|
||||||
|
{{ displayPrice(row.selectedUnitObj?.retailPrice || 0) }}
|
||||||
|
</template>
|
||||||
|
</vxe-column>
|
||||||
<vxe-column field="purchasePrice" title="原进价">
|
<vxe-column field="purchasePrice" title="原进价">
|
||||||
<template #default="{ row }">
|
<template #default="{ row }">
|
||||||
{{ displayPrice(row.selectedUnitObj?.purchasePrice || 0) }}
|
{{ displayPrice(row.selectedUnitObj?.purchasePrice || 0) }}
|
||||||
|
|||||||
@@ -121,7 +121,7 @@ const selectObjs = ref([]) as any
|
|||||||
const multiple = ref(true)
|
const multiple = ref(true)
|
||||||
const state: BasicTableProps = reactive<BasicTableProps>({
|
const state: BasicTableProps = reactive<BasicTableProps>({
|
||||||
queryForm: {
|
queryForm: {
|
||||||
inventoryType: "3",
|
inventoryType: "6",
|
||||||
},
|
},
|
||||||
pageList: fetchList,
|
pageList: fetchList,
|
||||||
})
|
})
|
||||||
|
|||||||
Reference in new issue
Block a user