优化店铺商品及分类管理
This commit is contained in:
@@ -1,7 +1,7 @@
|
||||
VITE_APP_NAME=后台管理系统
|
||||
VITE_SOCKET_URL=wss://server.gxwebsoft.com
|
||||
VITE_SERVER_URL=https://server.gxwebsoft.com/api
|
||||
VITE_API_URL=https://modules.gxwebsoft.com/api
|
||||
#VITE_API_URL=https://modules.gxwebsoft.com/api
|
||||
|
||||
#VITE_SERVER_URL=http://127.0.0.1:9091/api
|
||||
#VITE_API_URL=http://127.0.0.1:9099/api
|
||||
VITE_API_URL=http://127.0.0.1:9099/api
|
||||
|
||||
@@ -52,6 +52,8 @@ export interface GoodsCategory {
|
||||
label?: string;
|
||||
// 子菜单
|
||||
children?: GoodsCategory[];
|
||||
// 商铺ID
|
||||
merchantId?: number;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -12,11 +12,12 @@
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { ref, watch } from 'vue';
|
||||
import { ref, watch, reactive } from 'vue';
|
||||
import type { ValueType } from 'ant-design-vue/es/vc-cascader/Cascader';
|
||||
import { listGoodsCategory } from '@/api/shop/goodsCategory';
|
||||
import { toTreeData } from 'ele-admin-pro/es';
|
||||
import { GoodsCategory } from '@/api/shop/goodsCategory/model';
|
||||
import { FileRecordParam } from '@/api/system/file/model';
|
||||
|
||||
const props = withDefaults(
|
||||
defineProps<{
|
||||
@@ -26,6 +27,7 @@
|
||||
valueField?: 'label';
|
||||
type?: 'provinceCity' | 'province';
|
||||
showSearch?: boolean;
|
||||
merchantId?: number;
|
||||
}>(),
|
||||
{
|
||||
showSearch: true
|
||||
@@ -38,6 +40,11 @@
|
||||
(e: 'load-data-done', value: GoodsCategory[]): void;
|
||||
}>();
|
||||
|
||||
// 搜索表单
|
||||
const where = reactive<GoodsCategory>({
|
||||
merchantId: undefined
|
||||
});
|
||||
|
||||
// 级联选择器数据
|
||||
const regionsData = ref<GoodsCategory[]>([]);
|
||||
|
||||
@@ -47,7 +54,7 @@
|
||||
};
|
||||
|
||||
const onChange = (item: any, value: ValueType) => {
|
||||
console.log(item,value);
|
||||
console.log(item, value);
|
||||
emit('done', item, value);
|
||||
};
|
||||
|
||||
@@ -107,7 +114,10 @@
|
||||
watch(
|
||||
() => props.options,
|
||||
() => {
|
||||
listGoodsCategory().then((data) => {
|
||||
if (props.merchantId) {
|
||||
where.merchantId = props.merchantId;
|
||||
}
|
||||
listGoodsCategory(where).then((data) => {
|
||||
const list = toTreeData({
|
||||
data: data?.map((d) => {
|
||||
d.value = d.categoryId;
|
||||
|
||||
@@ -45,6 +45,7 @@
|
||||
</div>
|
||||
</a-form-item>
|
||||
<a-form-item
|
||||
v-if="!merchantId"
|
||||
label="选择店铺"
|
||||
name="merchantId"
|
||||
>
|
||||
@@ -64,7 +65,7 @@
|
||||
v-model:value="form.goodsName"
|
||||
/>
|
||||
</a-form-item>
|
||||
<a-form-item label="商品分类" name="categoryId">
|
||||
<a-form-item label="商品分类" name="categoryId" v-if="!merchantId">
|
||||
<SelectGoodsCategory
|
||||
:data="data"
|
||||
placeholder="请选择商品分类"
|
||||
@@ -73,6 +74,15 @@
|
||||
@done="chooseGoodsCategory"
|
||||
/>
|
||||
</a-form-item>
|
||||
<a-form-item label="菜品分类" name="categoryId" v-else>
|
||||
<SelectGoodsCategory
|
||||
:merchantId="merchantId"
|
||||
placeholder="请选择商品分类"
|
||||
style="width: 558px"
|
||||
v-model:value="form.categoryId"
|
||||
@done="chooseTakeawayCategory"
|
||||
/>
|
||||
</a-form-item>
|
||||
<a-form-item label="商品卖点" name="comments">
|
||||
<a-input
|
||||
allow-clear
|
||||
@@ -335,6 +345,9 @@
|
||||
import { GoodsSpec } from "@/api/shop/goodsSpec/model";
|
||||
import { generateGoodsSku, listGoodsSku } from "@/api/shop/goodsSku";
|
||||
import { listGoodsSpec } from "@/api/shop/goodsSpec";
|
||||
import CategorySelect from "@/views/cms/article/components/category-select.vue";
|
||||
import { GoodsCategory } from "@/api/shop/goodsCategory/model";
|
||||
import { listGoodsCategory } from "@/api/shop/goodsCategory";
|
||||
|
||||
// 是否是修改
|
||||
const isUpdate = ref(false);
|
||||
@@ -348,6 +361,8 @@
|
||||
visible: boolean;
|
||||
// 修改回显的数据
|
||||
data?: Goods | null;
|
||||
// 商户ID
|
||||
merchantId?: number;
|
||||
}>();
|
||||
|
||||
const emit = defineEmits<{
|
||||
@@ -375,6 +390,7 @@
|
||||
const files = ref<ItemType[]>([]);
|
||||
const goodsSpec = ref<GoodsSpec>();
|
||||
const category = ref<string[]>([]);
|
||||
const takeaway = ref<GoodsCategory[]>([]);
|
||||
|
||||
const columns = [
|
||||
{
|
||||
@@ -552,11 +568,16 @@
|
||||
form.merchantId = item.merchantId;
|
||||
};
|
||||
|
||||
const chooseGoodsCategory = (item,value) => {
|
||||
const chooseGoodsCategory = (item: GoodsCategory,value: any) => {
|
||||
form.categoryId = value[1].value;
|
||||
form.categoryParent = value[0].label;
|
||||
form.categoryChildren = value[1].label;
|
||||
}
|
||||
const chooseTakeawayCategory = (item: GoodsCategory, value: any) => {
|
||||
form.categoryParent = '店铺分类';
|
||||
form.categoryChildren = value[0].label;
|
||||
form.categoryId = item[0];
|
||||
}
|
||||
|
||||
const chooseImage = (data: FileRecord) => {
|
||||
images.value.push({
|
||||
@@ -673,9 +694,7 @@
|
||||
|
||||
const editorRef = ref<InstanceType<typeof TinymceEditor> | null>(null);
|
||||
const config = ref({
|
||||
height: 240,
|
||||
plugins: 'code preview fullscreen searchreplace save autosave link autolink image media table codesample lists advlist charmap emoticons anchor directionality pagebreak quickbars nonbreaking visualblocks visualchars wordcount',
|
||||
toolbar: false,
|
||||
height: 500,
|
||||
images_upload_handler: (blobInfo, success, error) => {
|
||||
const file = blobInfo.blob();
|
||||
const formData = new FormData();
|
||||
@@ -686,6 +705,44 @@
|
||||
error(msg);
|
||||
})
|
||||
},
|
||||
// 自定义文件上传(这里使用把选择的文件转成 blob 演示)
|
||||
file_picker_callback: (callback: any, _value: any, meta: any) => {
|
||||
const input = document.createElement('input');
|
||||
input.setAttribute('type', 'file');
|
||||
// 设定文件可选类型
|
||||
if (meta.filetype === 'image') {
|
||||
input.setAttribute('accept', 'image/*');
|
||||
} else if (meta.filetype === 'media') {
|
||||
input.setAttribute('accept', 'video/*,.pdf');
|
||||
}
|
||||
input.onchange = () => {
|
||||
const file = input.files?.[0];
|
||||
if (!file) {
|
||||
return;
|
||||
}
|
||||
if (meta.filetype === 'media') {
|
||||
if (file.size / 1024 / 1024 > 200) {
|
||||
editorRef.value?.alert({ content: '大小不能超过 200MB' });
|
||||
return;
|
||||
}
|
||||
if(file.type.startsWith('application/pdf')){
|
||||
uploadOss(file).then(res => {
|
||||
const addPath = `<a href="${res.downloadUrl}" target="_blank">${res.name}</a>`;
|
||||
content.value = content.value + addPath
|
||||
})
|
||||
return;
|
||||
}
|
||||
if (!file.type.startsWith('video/')) {
|
||||
editorRef.value?.alert({ content: '只能选择视频文件' });
|
||||
return;
|
||||
}
|
||||
uploadOss(file).then(res => {
|
||||
callback(res.path)
|
||||
});
|
||||
}
|
||||
};
|
||||
input.click();
|
||||
}
|
||||
});
|
||||
|
||||
/* 粘贴图片上传服务器并插入编辑器 */
|
||||
@@ -732,7 +789,8 @@
|
||||
content: content.value,
|
||||
files: JSON.stringify(files.value),
|
||||
goodsSpec: goodsSpec.value,
|
||||
goodsSkus: skuList.value
|
||||
goodsSkus: skuList.value,
|
||||
type: props.merchantId ? 1 : 0
|
||||
};
|
||||
const saveOrUpdate = isUpdate.value ? updateGoods : addGoods;
|
||||
saveOrUpdate(formData)
|
||||
@@ -796,6 +854,10 @@
|
||||
if (props.data.content){
|
||||
content.value = props.data.content;
|
||||
}
|
||||
// 外卖商品分类
|
||||
listGoodsCategory({merchantId: props.merchantId}).then(list => {
|
||||
takeaway.value = list
|
||||
})
|
||||
|
||||
isUpdate.value = true;
|
||||
} else {
|
||||
|
||||
@@ -21,6 +21,7 @@
|
||||
<SelectMerchant
|
||||
:placeholder="`选择商户`"
|
||||
class="input-item"
|
||||
v-if="!merchantId"
|
||||
v-model:value="where.merchantName"
|
||||
@done="chooseMerchantId"
|
||||
/>
|
||||
@@ -57,6 +58,7 @@
|
||||
defineProps<{
|
||||
// 选中的角色
|
||||
selection?: [];
|
||||
merchantId?: number;
|
||||
}>(),
|
||||
{}
|
||||
);
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
<search
|
||||
@search="reload"
|
||||
:selection="selection"
|
||||
:merchantId="merchantId"
|
||||
@add="openEdit"
|
||||
@remove="removeBatch"
|
||||
@batchMove="openMove"
|
||||
@@ -69,17 +70,21 @@
|
||||
</a-card>
|
||||
|
||||
<!-- 编辑弹窗 -->
|
||||
<GoodsEdit v-model:visible="showEdit" :data="current" @done="reload" />
|
||||
<GoodsEdit
|
||||
v-model:visible="showEdit"
|
||||
:merchantId="merchantId"
|
||||
:data="current"
|
||||
@done="reload"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { createVNode, ref } from 'vue';
|
||||
import { createVNode, ref, watch } from 'vue';
|
||||
import { message, Modal } from 'ant-design-vue';
|
||||
import { ExclamationCircleOutlined } from '@ant-design/icons-vue';
|
||||
import type { EleProTable } from 'ele-admin-pro';
|
||||
import { toDateString } from 'ele-admin-pro';
|
||||
import type {
|
||||
DatasourceFunction,
|
||||
ColumnItem
|
||||
@@ -94,6 +99,7 @@
|
||||
} from '@/api/shop/goods';
|
||||
import type { Goods, GoodsParam } from '@/api/shop/goods/model';
|
||||
import { formatNumber } from 'ele-admin-pro/es';
|
||||
import router from '@/router';
|
||||
|
||||
// 表格实例
|
||||
const tableRef = ref<InstanceType<typeof EleProTable> | null>(null);
|
||||
@@ -106,8 +112,8 @@
|
||||
const showEdit = ref(false);
|
||||
// 是否显示批量移动弹窗
|
||||
const showMove = ref(false);
|
||||
// 加载状态
|
||||
const loading = ref(true);
|
||||
// 店铺ID
|
||||
const merchantId = ref<number>();
|
||||
|
||||
// 表格数据源
|
||||
const datasource: DatasourceFunction = ({
|
||||
@@ -120,6 +126,9 @@
|
||||
if (filters) {
|
||||
where.status = filters.status;
|
||||
}
|
||||
if (merchantId.value) {
|
||||
where.merchantId = merchantId.value;
|
||||
}
|
||||
return pageGoods({
|
||||
...where,
|
||||
...orders,
|
||||
@@ -362,11 +371,6 @@
|
||||
});
|
||||
};
|
||||
|
||||
/* 查询 */
|
||||
const query = () => {
|
||||
loading.value = true;
|
||||
};
|
||||
|
||||
/* 自定义行属性 */
|
||||
const customRow = (record: Goods) => {
|
||||
return {
|
||||
@@ -380,7 +384,15 @@
|
||||
}
|
||||
};
|
||||
};
|
||||
query();
|
||||
|
||||
watch(
|
||||
() => router.currentRoute.value.params.id,
|
||||
(id) => {
|
||||
merchantId.value = Number(id);
|
||||
reload();
|
||||
},
|
||||
{ immediate: true }
|
||||
);
|
||||
</script>
|
||||
|
||||
<script lang="ts">
|
||||
|
||||
@@ -0,0 +1,292 @@
|
||||
<!-- 编辑弹窗 -->
|
||||
<template>
|
||||
<ele-modal
|
||||
:width="620"
|
||||
:visible="visible"
|
||||
:confirm-loading="loading"
|
||||
:title="isUpdate ? '修改分类' : '新建分类'"
|
||||
:body-style="{ paddingBottom: '8px' }"
|
||||
@update:visible="updateVisible"
|
||||
@ok="save"
|
||||
>
|
||||
<a-form
|
||||
ref="formRef"
|
||||
:model="form"
|
||||
:rules="rules"
|
||||
:label-col="styleResponsive ? { md: 4, sm: 4, xs: 24 } : { flex: '90px' }"
|
||||
:wrapper-col="
|
||||
styleResponsive ? { md: 18, sm: 20, xs: 24 } : { flex: '1' }
|
||||
"
|
||||
>
|
||||
<a-row :gutter="16">
|
||||
<a-col
|
||||
v-bind="styleResponsive ? { md: 24, sm: 24, xs: 24 } : { span: 12 }"
|
||||
>
|
||||
<a-form-item label="分类名称" name="title">
|
||||
<a-input
|
||||
allow-clear
|
||||
placeholder="请输入分类名称"
|
||||
v-model:value="form.title"
|
||||
@pressEnter="save"
|
||||
/>
|
||||
</a-form-item>
|
||||
</a-col>
|
||||
<a-col
|
||||
v-bind="styleResponsive ? { md: 24, sm: 24, xs: 24 } : { span: 12 }"
|
||||
>
|
||||
<a-form-item label="排序号" name="sortNumber">
|
||||
<a-input-number
|
||||
:min="0"
|
||||
:max="99999"
|
||||
class="ele-fluid"
|
||||
placeholder="请输入排序号"
|
||||
v-model:value="form.sortNumber"
|
||||
/>
|
||||
</a-form-item>
|
||||
<a-form-item label="是否展示">
|
||||
<a-switch
|
||||
checked-children="是"
|
||||
un-checked-children="否"
|
||||
:checked="form.status === 0"
|
||||
@update:checked="updateHideValue"
|
||||
/>
|
||||
</a-form-item>
|
||||
<a-form-item label="分类图标" name="image" extra="尺寸180*180">
|
||||
<SelectFile
|
||||
:placeholder="`请选择图片`"
|
||||
:limit="1"
|
||||
:data="images"
|
||||
@done="chooseFile"
|
||||
@del="onDeleteItem"
|
||||
/>
|
||||
</a-form-item>
|
||||
</a-col>
|
||||
</a-row>
|
||||
<div style="margin-bottom: 22px">
|
||||
<a-divider />
|
||||
</div>
|
||||
<a-form-item
|
||||
label="备注"
|
||||
name="comments"
|
||||
:label-col="
|
||||
styleResponsive ? { md: 3, sm: 4, xs: 24 } : { flex: '90px' }
|
||||
"
|
||||
:wrapper-col="
|
||||
styleResponsive ? { md: 21, sm: 20, xs: 24 } : { flex: '1' }
|
||||
"
|
||||
>
|
||||
<a-textarea
|
||||
:rows="4"
|
||||
:maxlength="200"
|
||||
placeholder="请输入备注信息"
|
||||
v-model:value="form.comments"
|
||||
/>
|
||||
</a-form-item>
|
||||
</a-form>
|
||||
</ele-modal>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { ref, reactive, watch } from 'vue';
|
||||
import { message } from 'ant-design-vue/es';
|
||||
import type { FormInstance, Rule } from 'ant-design-vue/es/form';
|
||||
import { storeToRefs } from 'pinia';
|
||||
import { useThemeStore } from '@/store/modules/theme';
|
||||
import useFormData from '@/utils/use-form-data';
|
||||
import { GoodsCategory } from '@/api/shop/goodsCategory/model';
|
||||
import {
|
||||
addGoodsCategory,
|
||||
updateGoodsCategory
|
||||
} from '@/api/shop/goodsCategory';
|
||||
import { ItemType } from 'ele-admin-pro/es/ele-image-upload/types';
|
||||
import { FileRecord } from '@/api/system/file/model';
|
||||
|
||||
// 是否开启响应式布局
|
||||
const themeStore = useThemeStore();
|
||||
const { styleResponsive } = storeToRefs(themeStore);
|
||||
// 已上传数据
|
||||
const images = ref<ItemType[]>([]);
|
||||
|
||||
const emit = defineEmits<{
|
||||
(e: 'done'): void;
|
||||
(e: 'update:visible', visible: boolean): void;
|
||||
}>();
|
||||
|
||||
const props = defineProps<{
|
||||
// 弹窗是否打开
|
||||
visible: boolean;
|
||||
// 修改回显的数据
|
||||
data?: GoodsCategory | null;
|
||||
// 上级分类id
|
||||
parentId?: number;
|
||||
// 商户ID
|
||||
merchantId?: number;
|
||||
// 全部分类数据
|
||||
categoryList: GoodsCategory[];
|
||||
}>();
|
||||
|
||||
//
|
||||
const formRef = ref<FormInstance | null>(null);
|
||||
|
||||
// 是否是修改
|
||||
const isUpdate = ref(false);
|
||||
|
||||
// 提交状态
|
||||
const loading = ref(false);
|
||||
|
||||
// 表单数据
|
||||
const { form, resetFields, assignFields } = useFormData<GoodsCategory>({
|
||||
categoryId: undefined,
|
||||
title: '',
|
||||
parentId: undefined,
|
||||
image: '',
|
||||
status: 0,
|
||||
sortNumber: 100
|
||||
});
|
||||
|
||||
// 表单验证规则
|
||||
const rules = reactive<Record<string, Rule[]>>({
|
||||
title: [
|
||||
{
|
||||
required: true,
|
||||
message: '请输入分类名称',
|
||||
type: 'string',
|
||||
trigger: 'blur'
|
||||
}
|
||||
],
|
||||
sortNumber: [
|
||||
{
|
||||
required: true,
|
||||
message: '请输入排序号',
|
||||
type: 'number',
|
||||
trigger: 'blur'
|
||||
}
|
||||
],
|
||||
meta: [
|
||||
{
|
||||
type: 'string',
|
||||
validator: async (_rule: Rule, value: string) => {
|
||||
if (value) {
|
||||
const msg = '请输入正确的JSON格式';
|
||||
try {
|
||||
const obj = JSON.parse(value);
|
||||
if (typeof obj !== 'object' || obj === null) {
|
||||
return Promise.reject(msg);
|
||||
}
|
||||
} catch (_e) {
|
||||
return Promise.reject(msg);
|
||||
}
|
||||
}
|
||||
return Promise.resolve();
|
||||
},
|
||||
trigger: 'blur'
|
||||
}
|
||||
]
|
||||
});
|
||||
|
||||
const chooseFile = (data: FileRecord) => {
|
||||
images.value.push({
|
||||
uid: data.id,
|
||||
url: data.path,
|
||||
status: 'done'
|
||||
});
|
||||
form.image = data.path;
|
||||
};
|
||||
|
||||
const onDeleteItem = (index: number) => {
|
||||
images.value.splice(index, 1);
|
||||
form.image = '';
|
||||
};
|
||||
|
||||
/* 保存编辑 */
|
||||
const save = () => {
|
||||
if (!formRef.value) {
|
||||
return;
|
||||
}
|
||||
formRef.value
|
||||
.validate()
|
||||
.then(() => {
|
||||
loading.value = true;
|
||||
const categoryForm = {
|
||||
...form,
|
||||
// menuType 对应的值与后端不一致在前端处理
|
||||
// menuType: form.menuType === 2 ? 1 : 0,
|
||||
parentId: form.parentId || 0,
|
||||
merchantId: props.merchantId
|
||||
};
|
||||
const saveOrUpdate = isUpdate.value
|
||||
? updateGoodsCategory
|
||||
: addGoodsCategory;
|
||||
saveOrUpdate(categoryForm)
|
||||
.then((msg) => {
|
||||
loading.value = false;
|
||||
message.success(msg);
|
||||
updateVisible(false);
|
||||
emit('done');
|
||||
})
|
||||
.catch((e) => {
|
||||
loading.value = false;
|
||||
message.error(e.message);
|
||||
});
|
||||
})
|
||||
.catch(() => {});
|
||||
};
|
||||
|
||||
/* 更新visible */
|
||||
const updateVisible = (value: boolean) => {
|
||||
emit('update:visible', value);
|
||||
};
|
||||
|
||||
const updateHideValue = (value: boolean) => {
|
||||
form.status = value ? 0 : 1;
|
||||
};
|
||||
|
||||
watch(
|
||||
() => props.visible,
|
||||
(visible) => {
|
||||
if (visible) {
|
||||
if (props.data) {
|
||||
assignFields({
|
||||
...props.data,
|
||||
parentId:
|
||||
props.data.parentId === 0 ? undefined : props.data.parentId
|
||||
});
|
||||
images.value = [];
|
||||
if (props.data.image) {
|
||||
images.value.push({
|
||||
uid: `${props.data.categoryId}`,
|
||||
url: props.data.image,
|
||||
status: 'done'
|
||||
});
|
||||
}
|
||||
isUpdate.value = true;
|
||||
} else {
|
||||
images.value = [];
|
||||
form.parentId = props.parentId;
|
||||
isUpdate.value = false;
|
||||
}
|
||||
} else {
|
||||
resetFields();
|
||||
formRef.value?.clearValidate();
|
||||
}
|
||||
}
|
||||
);
|
||||
</script>
|
||||
|
||||
<script lang="ts">
|
||||
import * as icons from '@/layout/menu-icons';
|
||||
|
||||
export default {
|
||||
components: icons,
|
||||
data() {
|
||||
return {
|
||||
iconData: [
|
||||
{
|
||||
title: '已引入的图标',
|
||||
icons: Object.keys(icons)
|
||||
}
|
||||
]
|
||||
};
|
||||
}
|
||||
};
|
||||
</script>
|
||||
181
src/views/shop/goodsCategory/components/search.vue
Normal file
181
src/views/shop/goodsCategory/components/search.vue
Normal file
@@ -0,0 +1,181 @@
|
||||
<!-- 搜索表单 -->
|
||||
<template>
|
||||
<a-space>
|
||||
<a-button type="primary" class="ele-btn-icon" @click="add">
|
||||
<template #icon>
|
||||
<plus-outlined />
|
||||
</template>
|
||||
<span>新建</span>
|
||||
</a-button>
|
||||
<template v-if="!merchantId">
|
||||
<a-button type="dashed" class="ele-btn-icon" @click="expandAll">
|
||||
展开全部
|
||||
</a-button>
|
||||
<a-button type="dashed" class="ele-btn-icon" @click="foldAll">
|
||||
折叠全部
|
||||
</a-button>
|
||||
</template>
|
||||
<SelectMerchant
|
||||
:placeholder="`选择商户`"
|
||||
class="input-item"
|
||||
v-if="!merchantId"
|
||||
v-model:value="where.merchantName"
|
||||
@done="chooseMerchantId"
|
||||
/>
|
||||
<!-- <SelectGoodsCategory-->
|
||||
<!-- v-if="!merchantId"-->
|
||||
<!-- class="input-item"-->
|
||||
<!-- :placeholder="`请选择商品分类`"-->
|
||||
<!-- v-model:value="where.categoryId"-->
|
||||
<!-- @done="chooseGoodsCategory"-->
|
||||
<!-- />-->
|
||||
<a-input-search
|
||||
allow-clear
|
||||
placeholder="请输入关键词"
|
||||
v-model:value="where.keywords"
|
||||
@pressEnter="reload"
|
||||
@search="reload"
|
||||
/>
|
||||
</a-space>
|
||||
<!-- <a-space :size="10" style="flex-wrap: wrap">-->
|
||||
<!-- <a-button type="primary" class="ele-btn-icon" @click="add">-->
|
||||
<!-- <template #icon>-->
|
||||
<!-- <PlusOutlined />-->
|
||||
<!-- </template>-->
|
||||
<!-- <span>添加</span>-->
|
||||
<!-- </a-button>-->
|
||||
<!-- <a-radio-group v-model:value="type" @change="handleSearch">-->
|
||||
<!-- <a-radio-button value="出售中"-->
|
||||
<!-- >出售中({{ goodsCount?.totalNum }})</a-radio-button-->
|
||||
<!-- >-->
|
||||
<!-- <a-radio-button value="待上架"-->
|
||||
<!-- >待上架({{ goodsCount?.totalNum2 }})</a-radio-button-->
|
||||
<!-- >-->
|
||||
<!-- <a-radio-button value="已售罄"-->
|
||||
<!-- >已售罄({{ goodsCount?.totalNum3 }})</a-radio-button-->
|
||||
<!-- >-->
|
||||
<!-- </a-radio-group>-->
|
||||
<!-- <SelectMerchant-->
|
||||
<!-- :placeholder="`选择商户`"-->
|
||||
<!-- class="input-item"-->
|
||||
<!-- v-if="!merchantId"-->
|
||||
<!-- v-model:value="where.merchantName"-->
|
||||
<!-- @done="chooseMerchantId"-->
|
||||
<!-- />-->
|
||||
<!-- <a-button @click="reset">重置</a-button>-->
|
||||
<!-- </a-space>-->
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { PlusOutlined } from '@ant-design/icons-vue';
|
||||
import type { GradeParam } from '@/api/user/grade/model';
|
||||
import { ref, watch } from 'vue';
|
||||
import { getCount } from '@/api/shop/goods';
|
||||
import type { GoodsCount, GoodsParam } from '@/api/shop/goods/model';
|
||||
import useSearch from '@/utils/use-search';
|
||||
import { useRouter } from 'vue-router';
|
||||
import { Merchant } from '@/api/shop/merchant/model';
|
||||
import { GoodsCategory } from '@/api/shop/goodsCategory/model';
|
||||
const { currentRoute } = useRouter();
|
||||
|
||||
const props = withDefaults(
|
||||
defineProps<{
|
||||
// 选中的角色
|
||||
selection?: [];
|
||||
merchantId?: number;
|
||||
}>(),
|
||||
{}
|
||||
);
|
||||
|
||||
const type = ref<string>();
|
||||
// 统计数据
|
||||
const goodsCount = ref<GoodsCount>();
|
||||
|
||||
// 表单数据
|
||||
const { where, resetFields } = useSearch<GoodsParam>({
|
||||
goodsId: undefined,
|
||||
isShow: undefined,
|
||||
stock: undefined,
|
||||
categoryId: undefined,
|
||||
keywords: ''
|
||||
});
|
||||
|
||||
const emit = defineEmits<{
|
||||
(e: 'search', where?: GradeParam): void;
|
||||
(e: 'add'): void;
|
||||
(e: 'remove'): void;
|
||||
(e: 'batchMove'): void;
|
||||
(e: 'expand'): void;
|
||||
(e: 'fold'): void;
|
||||
}>();
|
||||
|
||||
const expandAll = () => {
|
||||
emit('expand');
|
||||
};
|
||||
|
||||
const foldAll = () => {
|
||||
emit('fold');
|
||||
};
|
||||
|
||||
// 新增
|
||||
const add = () => {
|
||||
emit('add');
|
||||
};
|
||||
|
||||
const handleSearch = (e) => {
|
||||
const text = e.target.value;
|
||||
resetFields();
|
||||
if (text === '出售中') {
|
||||
where.isShow = 1;
|
||||
}
|
||||
if (text === '待上架') {
|
||||
where.isShow = 0;
|
||||
}
|
||||
if (text === '已售罄') {
|
||||
where.stock = 0;
|
||||
}
|
||||
emit('search', where);
|
||||
};
|
||||
|
||||
const reload = () => {
|
||||
getCount().then((data: any) => {
|
||||
goodsCount.value = data;
|
||||
});
|
||||
emit('search', where);
|
||||
};
|
||||
|
||||
/* 搜索 */
|
||||
const chooseMerchantId = (item: Merchant) => {
|
||||
where.merchantName = item.merchantName;
|
||||
where.merchantId = item.merchantId;
|
||||
reload();
|
||||
};
|
||||
|
||||
const chooseGoodsCategory = (
|
||||
category: GoodsCategory,
|
||||
data: GoodsCategory
|
||||
) => {
|
||||
where.categoryName = data[1].label;
|
||||
where.categoryId = data[1].value;
|
||||
reload();
|
||||
};
|
||||
|
||||
/* 重置 */
|
||||
const reset = () => {
|
||||
resetFields();
|
||||
type.value = '';
|
||||
reload();
|
||||
};
|
||||
|
||||
// watch(
|
||||
// () => props.selection,
|
||||
// () => {}
|
||||
// );
|
||||
watch(
|
||||
currentRoute,
|
||||
() => {
|
||||
reload();
|
||||
},
|
||||
{ immediate: true }
|
||||
);
|
||||
</script>
|
||||
@@ -18,28 +18,13 @@
|
||||
@expand="onExpand"
|
||||
>
|
||||
<template #toolbar>
|
||||
<a-space>
|
||||
<a-button type="primary" class="ele-btn-icon" @click="openEdit()">
|
||||
<template #icon>
|
||||
<plus-outlined />
|
||||
</template>
|
||||
<span>新建</span>
|
||||
</a-button>
|
||||
<a-button type="dashed" class="ele-btn-icon" @click="expandAll">
|
||||
展开全部
|
||||
</a-button>
|
||||
<a-button type="dashed" class="ele-btn-icon" @click="foldAll">
|
||||
折叠全部
|
||||
</a-button>
|
||||
<!-- 搜索表单 -->
|
||||
<a-input-search
|
||||
allow-clear
|
||||
v-model:value="searchText"
|
||||
placeholder="请输入搜索关键词"
|
||||
@search="reload"
|
||||
@pressEnter="reload"
|
||||
/>
|
||||
</a-space>
|
||||
<search
|
||||
@search="reload"
|
||||
:merchantId="merchantId"
|
||||
@add="openEdit"
|
||||
@expand="expandAll"
|
||||
@fold="foldAll"
|
||||
/>
|
||||
</template>
|
||||
<template #bodyCell="{ column, record }">
|
||||
<template v-if="column.key === 'path'">
|
||||
@@ -66,9 +51,7 @@
|
||||
style="margin-right: 10px"
|
||||
v-if="record.image"
|
||||
/>
|
||||
<a @click="openPreview(`/goods/search?categoryId=${record.categoryId}`)">{{
|
||||
record.title
|
||||
}}</a>
|
||||
{{ record.title }}
|
||||
</template>
|
||||
<template v-if="column.key === 'showIndex'">
|
||||
<a-space @click="onShowIndex(record)">
|
||||
@@ -110,19 +93,30 @@
|
||||
</template>
|
||||
</ele-pro-table>
|
||||
</a-card>
|
||||
<!-- 编辑弹窗 -->
|
||||
<!-- 商城分类编辑弹窗 -->
|
||||
<category-edit
|
||||
v-model:visible="showEdit"
|
||||
v-if="merchantId == 0"
|
||||
:data="current"
|
||||
:parent-id="parentId"
|
||||
:category-list="categoryData"
|
||||
@done="reload"
|
||||
/>
|
||||
<!-- 店铺分类编辑弹窗 -->
|
||||
<merchant-category-edit
|
||||
v-model:visible="showEdit"
|
||||
v-else
|
||||
:data="current"
|
||||
:parent-id="parentId"
|
||||
:merchantId="merchantId"
|
||||
:category-list="categoryData"
|
||||
@done="reload"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { ref } from 'vue';
|
||||
import { ref, watch } from 'vue';
|
||||
import { message } from 'ant-design-vue/es';
|
||||
import {
|
||||
ArrowUpOutlined,
|
||||
@@ -144,6 +138,7 @@
|
||||
} from 'ele-admin-pro/es';
|
||||
import type { EleProTable } from 'ele-admin-pro/es';
|
||||
import CategoryEdit from './components/category-edit.vue';
|
||||
import MerchantCategoryEdit from './components/merchant-category-edit.vue';
|
||||
import {
|
||||
listGoodsCategory,
|
||||
removeGoodsCategory,
|
||||
@@ -155,6 +150,8 @@
|
||||
} from '@/api/shop/goodsCategory/model';
|
||||
import { openNew, openPreview } from '@/utils/common';
|
||||
import { getSiteInfo } from '@/api/layout';
|
||||
import router from '@/router';
|
||||
import Search from './components/search.vue';
|
||||
|
||||
// 表格实例
|
||||
const tableRef = ref<InstanceType<typeof EleProTable> | null>(null);
|
||||
@@ -251,6 +248,7 @@
|
||||
const searchText = ref('');
|
||||
const tenantId = ref<number>();
|
||||
const domain = ref<string>();
|
||||
const merchantId = ref<number>();
|
||||
|
||||
getSiteInfo().then((data) => {
|
||||
tenantId.value = data.tenantId;
|
||||
@@ -260,6 +258,9 @@
|
||||
// 表格数据源
|
||||
const datasource: DatasourceFunction = ({ where }) => {
|
||||
where.title = searchText.value;
|
||||
if (merchantId.value) {
|
||||
where.merchantId = merchantId.value;
|
||||
}
|
||||
return listGoodsCategory({ ...where });
|
||||
};
|
||||
|
||||
@@ -397,6 +398,15 @@
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
watch(
|
||||
() => router.currentRoute.value.params.id,
|
||||
(id) => {
|
||||
merchantId.value = Number(id);
|
||||
reload();
|
||||
},
|
||||
{ immediate: true }
|
||||
);
|
||||
</script>
|
||||
|
||||
<script lang="ts">
|
||||
|
||||
@@ -10,6 +10,12 @@
|
||||
<a-button class="ele-btn-icon" @click="openUrl(`/shop/index`)">
|
||||
<span>店铺管理</span>
|
||||
</a-button>
|
||||
<a-button class="ele-btn-icon" @click="openUrl(`/shop/index`)">
|
||||
<span>门店职员</span>
|
||||
</a-button>
|
||||
<a-button class="ele-btn-icon" @click="openUrl(`/goods/category/:id`)">
|
||||
<span>商品分类</span>
|
||||
</a-button>
|
||||
<a-button class="ele-btn-icon" @click="openUrl(`/shop/apply`)">
|
||||
<span>入驻申请</span>
|
||||
</a-button>
|
||||
@@ -28,6 +34,7 @@
|
||||
import { watch } from 'vue';
|
||||
import { openUrl } from '@/utils/common';
|
||||
import router from '@/router';
|
||||
import { getMerchant } from '@/api/shop/merchant';
|
||||
|
||||
const props = withDefaults(
|
||||
defineProps<{
|
||||
@@ -52,7 +59,7 @@
|
||||
watch(
|
||||
() => router.currentRoute,
|
||||
(route) => {
|
||||
console.log(route,'route');
|
||||
console.log(route, 'route');
|
||||
}
|
||||
);
|
||||
</script>
|
||||
|
||||
@@ -30,8 +30,12 @@
|
||||
</template>
|
||||
<template v-if="column.key === 'action'">
|
||||
<a-space>
|
||||
<a @click="openUrl(`/shop/account/${record.merchantId}`)"
|
||||
>门店用户</a
|
||||
<a @click="openUrl(`/goods/category/${record.merchantId}`)"
|
||||
>分类</a
|
||||
>
|
||||
<a-divider type="vertical" />
|
||||
<a @click="openUrl(`/goods/index/${record.merchantId}`)"
|
||||
>商品</a
|
||||
>
|
||||
<a-divider type="vertical" />
|
||||
<a @click="openEdit(record)">修改</a>
|
||||
@@ -55,7 +59,7 @@
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { createVNode, ref } from 'vue';
|
||||
import { createVNode, ref, watch } from 'vue';
|
||||
import { message, Modal } from 'ant-design-vue';
|
||||
import { ExclamationCircleOutlined } from '@ant-design/icons-vue';
|
||||
import type { EleProTable } from 'ele-admin-pro';
|
||||
@@ -72,7 +76,8 @@
|
||||
removeBatchMerchant
|
||||
} from '@/api/shop/merchant';
|
||||
import type { Merchant, MerchantParam } from '@/api/shop/merchant/model';
|
||||
import { openNew, openPreview, openUrl } from '@/utils/common';
|
||||
import { openUrl } from '@/utils/common';
|
||||
import router from '@/router';
|
||||
|
||||
// 表格实例
|
||||
const tableRef = ref<InstanceType<typeof EleProTable> | null>(null);
|
||||
@@ -85,8 +90,8 @@
|
||||
const showEdit = ref(false);
|
||||
// 是否显示批量移动弹窗
|
||||
const showMove = ref(false);
|
||||
// 加载状态
|
||||
const loading = ref(true);
|
||||
// 商户ID
|
||||
const merchantId = ref(0);
|
||||
|
||||
// 表格数据源
|
||||
const datasource: DatasourceFunction = ({
|
||||
@@ -169,7 +174,7 @@
|
||||
{
|
||||
title: '操作',
|
||||
key: 'action',
|
||||
width: 180,
|
||||
width: 240,
|
||||
fixed: 'right',
|
||||
align: 'center',
|
||||
hideInSetting: true
|
||||
@@ -235,11 +240,6 @@
|
||||
});
|
||||
};
|
||||
|
||||
/* 查询 */
|
||||
const query = () => {
|
||||
loading.value = true;
|
||||
};
|
||||
|
||||
/* 自定义行属性 */
|
||||
const customRow = (record: Merchant) => {
|
||||
return {
|
||||
@@ -253,7 +253,20 @@
|
||||
}
|
||||
};
|
||||
};
|
||||
query();
|
||||
|
||||
watch(
|
||||
() => router.currentRoute.value.params.id,
|
||||
(id) => {
|
||||
if (id) {
|
||||
if (id == ':id') {
|
||||
merchantId.value = 0;
|
||||
} else {
|
||||
merchantId.value = Number(id);
|
||||
}
|
||||
}
|
||||
},
|
||||
{ immediate: true }
|
||||
);
|
||||
</script>
|
||||
|
||||
<script lang="ts">
|
||||
|
||||
@@ -7,24 +7,23 @@
|
||||
row-key="logId"
|
||||
:columns="columns"
|
||||
:datasource="datasource"
|
||||
v-model:selection="selection"
|
||||
:scroll="{ x: 1000 }"
|
||||
:where="defaultWhere"
|
||||
cache-key="userBalanceLogTable"
|
||||
>
|
||||
<template #toolbar>
|
||||
<a-space>
|
||||
<a-button
|
||||
danger
|
||||
type="primary"
|
||||
class="ele-btn-icon"
|
||||
@click="removeBatch"
|
||||
>
|
||||
<template #icon>
|
||||
<delete-outlined />
|
||||
</template>
|
||||
<span>批量删除</span>
|
||||
</a-button>
|
||||
<!-- <a-button-->
|
||||
<!-- danger-->
|
||||
<!-- type="primary"-->
|
||||
<!-- class="ele-btn-icon"-->
|
||||
<!-- @click="removeBatch"-->
|
||||
<!-- >-->
|
||||
<!-- <template #icon>-->
|
||||
<!-- <delete-outlined />-->
|
||||
<!-- </template>-->
|
||||
<!-- <span>批量删除</span>-->
|
||||
<!-- </a-button>-->
|
||||
<a-range-picker
|
||||
v-model:value="dateRange"
|
||||
value-format="YYYY-MM-DD"
|
||||
@@ -36,7 +35,6 @@
|
||||
placeholder="请输入关键词"
|
||||
@search="reload"
|
||||
@pressEnter="reload"
|
||||
@close="onClose"
|
||||
/>
|
||||
<a-button @click="reset">重置</a-button>
|
||||
</a-space>
|
||||
@@ -128,13 +126,19 @@
|
||||
const tableRef = ref<InstanceType<typeof EleProTable> | null>(null);
|
||||
// 表格列配置
|
||||
const columns = ref<ColumnItem[]>([
|
||||
// {
|
||||
// key: 'index',
|
||||
// width: 48,
|
||||
// align: 'center',
|
||||
// fixed: 'left',
|
||||
// hideInSetting: true,
|
||||
// customRender: ({ index }) => index + (tableRef.value?.tableIndex ?? 0)
|
||||
// },
|
||||
{
|
||||
key: 'index',
|
||||
width: 48,
|
||||
align: 'center',
|
||||
fixed: 'left',
|
||||
hideInSetting: true,
|
||||
customRender: ({ index }) => index + (tableRef.value?.tableIndex ?? 0)
|
||||
title: '用户ID',
|
||||
dataIndex: 'userId',
|
||||
width: 80,
|
||||
showSorterTooltip: false
|
||||
},
|
||||
{
|
||||
title: '用户',
|
||||
|
||||
Reference in New Issue
Block a user