| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664 |
- <script setup lang="tsx">
- import { computed, ref, useTemplateRef } from 'vue';
- import { NButton, NImage, NInputNumber, NSelect } from 'naive-ui';
- // import dayjs from 'dayjs';
- // import { fetchGetStoreList } from '@/service/api/xsb-manage/store-info';
- // import {
- // fetchGetAllChannelList
- // fetchImportGoods,
- // fetchSetUpChannels
- // } from '@/service/api/goods/store-goods';
- // import { fetchGetDictDataList } from '@/service/api/system-manage';
- import {
- // fetchGetAllChannelList,
- fetchChangeStatus,
- fetchFindThirdPartyBalance,
- fetchGetChannelList,
- fetchImportGoods,
- fetchProductList,
- fetchSetUpChannels,
- fetchUpdateName,
- fetchUpdateProductImg
- } from '@/service/api/goods-center/virtual-goods';
- import { areAllItemsAllFieldsFilled } from '@/utils/zt';
- import { commonExport } from '@/utils/common';
- import { useTable } from '@/components/zt/Table/hooks/useTable';
- import SvgIcon from '@/components/custom/svg-icon.vue';
- import { useModal } from '@/components/zt/Modal/hooks/useModal';
- import { useModalFrom } from '@/components/zt/ModalForm/hooks/useModalForm';
- type Price = { channelId: number | undefined; channelProdPrice: number; id?: number; channelName?: string };
- const importTemplateRef = useTemplateRef('importTemplateRef');
- const Balance = ref<number>(0);
- const options = ref<Api.goods.Channel[]>([]);
- // const TypeName = ['企业用户', 'B端用户', 'C端用户'];
- const statusList = ['上架', '下架'];
- const columns: NaiveUI.TableColumn<Api.goods.ShopSku>[] = [
- {
- type: 'selection',
- align: 'center',
- width: 48,
- fixed: 'left'
- },
- {
- key: 'productNumber',
- title: '商品ID',
- align: 'left',
- width: 200
- },
- {
- key: 'productImg',
- title: '商品图片',
- align: 'center',
- width: 120,
- render: (row: any) => {
- return <NImage src={row.productImg} width={60} height={60}></NImage>;
- }
- },
- {
- key: 'productName',
- title: '商品名称',
- align: 'center',
- width: 120,
- ellipsis: {
- tooltip: true
- }
- },
- {
- key: 'localProductName',
- title: '本地商品名称',
- align: 'center',
- width: 120,
- ellipsis: {
- tooltip: true
- }
- },
- {
- key: 'productType',
- title: '商品类型',
- align: 'center',
- width: 120,
- ellipsis: {
- tooltip: true
- }
- },
- {
- key: 'businessType',
- title: '业务类型',
- align: 'center',
- width: 120,
- ellipsis: {
- tooltip: true
- }
- },
- // {
- // key: 'shopName',
- // title: '商户',
- // align: 'center',
- // width: 120,
- // ellipsis: {
- // tooltip: true
- // },
- // render: (row: any) => {
- // return '-';
- // }
- // },
- {
- key: 'faceValue',
- title: '面值(元)',
- align: 'center',
- width: 120,
- ellipsis: {
- tooltip: true
- }
- },
- {
- key: 'purchasePrice',
- title: '采购价',
- align: 'center',
- width: 120,
- ellipsis: {
- tooltip: true
- }
- },
- {
- key: 'pmsVideoChannelPrices',
- title: '价格',
- align: 'center',
- width: 120,
- render: (row: any) => {
- return (
- <div>
- {row.pmsVideoChannelPrices.map((it: Api.government.ChannelVO) => {
- return (
- <div>
- {it.channelName}:¥{it.price}
- </div>
- );
- })}
- </div>
- );
- }
- },
- {
- key: 'inventory',
- title: '库存',
- align: 'center',
- width: 120,
- ellipsis: {
- tooltip: true
- }
- },
- {
- key: 'productStatus',
- title: '状态',
- align: 'center',
- width: 120,
- render: (row: any) => {
- return (
- <div class="flex items-center justify-center">
- <n-badge color={row.productStatus == 0 ? 'green' : 'red'} value={row.productStatus} dot />
- <span class="ml-2">{statusList[row.productStatus]}</span>
- </div>
- );
- }
- },
- {
- key: 'updateTime',
- title: '更新时间',
- align: 'center',
- width: 120,
- ellipsis: {
- tooltip: true
- }
- }
- ];
- const PriceColumns: NaiveUI.TableColumn<Price>[] = [
- {
- title: '销售渠道',
- key: 'channelId',
- align: 'center',
- width: 250,
- render: row => {
- return (
- <NSelect
- options={options.value}
- labelField="channelName"
- valueField="id"
- value={row.channelId}
- clearable
- onUpdate:value={value => {
- options.value.map(it => {
- if (it.id == row.channelId) {
- it.disabled = false;
- }
- return it;
- });
- row.channelId = value ? Number(value) : undefined;
- row.channelName = options.value.find(it => it.id == row.channelId)?.channelName;
- }}
- onUpdate:show={value => {
- console.log('show', value);
- options.value.map(it => {
- if (it.id == row.channelId) {
- if (value) {
- it.disabled = false;
- }
- if (!value) {
- it.disabled = true;
- }
- }
- return it;
- });
- }}
- ></NSelect>
- );
- }
- },
- {
- title: '售价(元)',
- key: 'channelProdPrice',
- align: 'center',
- width: 250,
- render: row => {
- return (
- <NInputNumber
- value={row.channelProdPrice}
- precision={2}
- onUpdate:value={value => {
- row.channelProdPrice = Number(value);
- }}
- min={0}
- />
- );
- }
- },
- {
- title: () => {
- return (
- <div onClick={() => handleAddPrice()} class={'w-full flex items-center justify-center'}>
- <SvgIcon
- icon={'proicons:add-square'}
- class={'cursor-pointer text-24px'}
- style={'color:var(--n-color)'}
- ></SvgIcon>
- </div>
- );
- },
- key: 'action',
- width: 80,
- align: 'center',
- render: (_row, index) => {
- return (
- <div onClick={() => handleDelPrice(index)} class={'w-full flex items-center justify-center'}>
- <SvgIcon
- icon={'proicons:subtract-square'}
- class={'cursor-pointer text-24px'}
- style={'color:#f5222d'}
- ></SvgIcon>
- </div>
- );
- }
- }
- ];
- const PriceData = ref<Price[]>([]);
- const selectData = ref<Api.goods.ShopSku>();
- const [registerTable, { refresh, getTableData, getSeachForm, setTableLoading }] = useTable({
- searchFormConfig: {
- schemas: [
- // {
- // label: '门店名称',
- // component: 'ApiSelect',
- // field: 'shopId',
- // componentProps: {
- // api: fetchGetStoreList,
- // resultFeild: 'data.list',
- // labelFeild: 'shopName',
- // valueFeild: 'shopId'
- // }
- // },
- {
- label: '关键词',
- component: 'NInput',
- field: 'keywords'
- },
- // {
- // label: '业务类型',
- // field: 'channelCode',
- // component: 'ApiSelect',
- // componentProps: {
- // api: fetchGetDictDataList,
- // labelFeild: 'name',
- // valueFeild: 'value',
- // resultFeild: 'data.list',
- // params: {
- // typeCode: 'sys_business_type'
- // }
- // }
- // },
- {
- label: '状态',
- field: 'productStatus',
- component: 'NSelect',
- componentProps: {
- options: [
- {
- label: '下架',
- value: 1
- },
- {
- label: '上架',
- value: 0
- }
- ]
- }
- },
- // {
- // label: '分类',
- // component: 'NCascader',
- // field: 'skuName',
- // componentProps: {}
- // },
- {
- label: '更新时间',
- component: 'NDatePicker',
- field: 'createTime',
- componentProps: {
- type: 'datetimerange',
- defaultTime: ['00:00:00', '23:59:59']
- }
- },
- {
- label: '价格范围',
- component: 'NInput',
- field: 'price',
- componentProps: {
- separator: '-',
- pair: true,
- placeholder: ['最低价', '最高价'],
- allowInput: (value: string) => !value || /^\d+$/.test(value)
- }
- }
- ],
- inline: false,
- size: 'small',
- labelPlacement: 'left',
- isFull: false
- },
- tableConfig: {
- keyField: 'skuId',
- title: '商品列表',
- showAddButton: false,
- scrollX: 1800,
- fieldMapToTime: [
- ['price', ['minPrice', 'maxPrice']],
- ['createTime', ['startTime', 'endTime']]
- ]
- }
- });
- const [
- registerModalPrice,
- { openModal: openPriceModal, setSubLoading: setSubModalLoding, closeModal: closePriceModal }
- ] = useModal({
- title: '设置渠道及价格',
- width: 800,
- height: 300
- });
- const [
- registerModalForm,
- {
- openModal: openModalForm,
- setFieldsValue: setModalFormValue,
- getFieldsValue: getModalFormValue,
- closeModal: closeModalForm,
- setSubLoading
- }
- ] = useModalFrom({
- modalConfig: {
- title: '封面',
- isShowHeaderText: true
- },
- formConfig: {
- schemas: [
- {
- field: 'productId',
- label: '分类ID',
- component: 'NInput',
- required: true
- },
- {
- field: 'productImg',
- component: 'zUpload',
- label: '广告位图片',
- componentProps: {
- max: 1
- },
- required: true
- }
- ],
- labelWidth: 120,
- layout: 'horizontal',
- gridProps: {
- cols: '1',
- itemResponsive: true
- }
- }
- });
- const [
- registerNameModalForm,
- {
- openModal: opeNamenModalForm,
- setFieldsValue: setNameModalFormValue,
- getFieldsValue: getNameModalFormValue,
- closeModal: closeNameModalForm,
- setSubLoading: setNameSubLoading
- }
- ] = useModalFrom({
- modalConfig: {
- title: '商品名称',
- isShowHeaderText: true,
- height: 300,
- width: 500
- },
- formConfig: {
- schemas: [
- {
- field: 'videoProductId',
- label: '分类ID',
- component: 'NInput',
- required: true,
- show: false
- },
- {
- field: 'videoProductName',
- label: '本地商品名称',
- component: 'NInput',
- required: true
- }
- ],
- labelWidth: 120,
- layout: 'horizontal',
- gridProps: {
- cols: '1',
- itemResponsive: true
- }
- }
- });
- // const isDisabledExport = computed(() => {
- // return !getTableCheckedRowKeys().length;
- // });
- const tableData = computed(() => {
- return getTableData();
- });
- async function handleSubmitImport(file: File) {
- const { error } = await fetchImportGoods({ file });
- if (!error) {
- importTemplateRef.value?.closeModal();
- }
- importTemplateRef.value?.setSubLoading(false);
- }
- function openImportModal() {
- importTemplateRef.value?.openModal();
- }
- function handleModalPrice(row: Api.goods.ShopSku) {
- selectData.value = row;
- if (row.pmsVideoChannelPrices) {
- PriceData.value = row.pmsVideoChannelPrices?.map((it: Api.government.ChannelVO) => {
- options.value.map(its => {
- if (its.id == it.channelId) {
- its.disabled = true;
- }
- return its;
- });
- return {
- channelName: it.channelName,
- channelId: Number(it.channelId),
- channelProdPrice: Number(it.price),
- id: it.id
- };
- });
- }
- openPriceModal();
- }
- function handleModalImg(row: Api.goods.ShopSku) {
- openModalForm(row);
- setModalFormValue({ productImg: row.productImg, productId: row.productId });
- }
- function handleModalName(row: Api.goods.ShopSku) {
- opeNamenModalForm(row);
- setNameModalFormValue({ videoProductId: row.id, videoProductName: row.localProductName });
- }
- function handleAddPrice() {
- // if (PriceData.value.length == 3) {
- // window.$message?.error('最多只能添加3条数据');
- // return;
- // }
- PriceData.value.push({
- channelName: '',
- channelId: undefined,
- channelProdPrice: 1
- // id: dayjs().valueOf()
- });
- console.log(PriceData.value);
- }
- function handleDelPrice(index: number) {
- // PriceData.value = PriceData.value.filter(item => item.id != id);
- PriceData.value.splice(index, 1);
- console.log('删除', index, PriceData.value);
- }
- async function handleSubmitPrice() {
- console.log(PriceData.value);
- if (!PriceData.value.length) {
- window.$message?.error('最少填写一条数据');
- return;
- }
- if (!areAllItemsAllFieldsFilled(PriceData.value)) {
- window.$message?.error('请填写完整数据');
- return;
- }
- setSubModalLoding(true);
- console.log(PriceData.value);
- const form = {
- // shopId: selectData.value?.shopId,
- videoProductId: selectData.value?.id,
- // purchasePrice: selectData.value?.channelProdList?.length ? selectData.value.channelProdList[0].purchasePrice : null,
- // deliveryPrice: selectData.value?.channelProdList?.length ? selectData.value.channelProdList[0].deliveryPrice : null,
- purchasePrice: selectData.value?.pmsVideoChannelPrices?.length
- ? selectData.value.pmsVideoChannelPrices[0].purchasePrice
- : null,
- deliveryPrice: selectData.value?.pmsVideoChannelPrices?.length
- ? selectData.value.pmsVideoChannelPrices[0].deliveryPrice
- : null,
- videoChannelPriceForms: PriceData.value.map(item => {
- return {
- // channelName: item.channelName,
- id: item?.id,
- channelId: item.channelId,
- price: item.channelProdPrice
- };
- })
- };
- const { error } = await fetchSetUpChannels(form);
- if (!error) {
- closePriceModal();
- refresh();
- PriceData.value = [];
- options.value.map(it => (it.disabled = false));
- } else {
- setSubModalLoding(false);
- }
- }
- async function getData() {
- const { data, error } = await fetchGetChannelList();
- if (!error) {
- options.value = data;
- }
- }
- getData();
- async function handleExport() {
- setTableLoading(true);
- try {
- await commonExport('/smqjh-pms/v1/videoProduct/export', getSeachForm(), '虚拟商品列表.xlsx');
- } finally {
- setTableLoading(false);
- }
- }
- function handleStatus(row: any) {
- window.$dialog?.info({
- title: '提示',
- content: `你确定要该操作吗?`,
- positiveText: '确定',
- negativeText: '取消',
- onPositiveClick: async () => {
- const { error } = await fetchChangeStatus({ id: row.id });
- if (!error) {
- refresh();
- }
- }
- });
- }
- async function handleSubmit() {
- const form = await getModalFormValue();
- // console.log(form, '表单', selectChekedKeys.value);
- await fetchUpdateProductImg(form);
- setSubLoading(false);
- closeModalForm();
- refresh();
- }
- async function handleSubmitName() {
- const form = await getNameModalFormValue();
- // console.log(form, '表单', selectChekedKeys.value);
- await fetchUpdateName(form);
- setNameSubLoading(false);
- closeNameModalForm();
- refresh();
- }
- async function handleFindThirdPartyBalance() {
- const { data, error } = await fetchFindThirdPartyBalance();
- if (!error) {
- Balance.value = data;
- }
- }
- handleFindThirdPartyBalance();
- </script>
- <template>
- <LayoutTable>
- <ZTable :columns="columns" :api="fetchProductList" @search="handleFindThirdPartyBalance" @register="registerTable">
- <template #op="{ row }">
- <NSpace align="center">
- <NButton size="small" ghost type="primary" @click="handleModalImg(row)">编辑图片</NButton>
- <NButton size="small" ghost type="primary" @click="handleModalName(row)">修改名称</NButton>
- <NButton size="small" ghost type="primary" @click="handleModalPrice(row)">设置渠道及价格</NButton>
- <NButton size="small" ghost type="primary" @click="handleStatus(row)">
- {{ row.productStatus == 1 ? '上架' : '下架' }}
- </NButton>
- </NSpace>
- </template>
- <template #prefix="{ loading }">
- <NSpace>
- <NButton type="primary" size="small" @click="handleFindThirdPartyBalance">
- 蓝色兄弟余额:
- <div class="text-red">{{ Balance }}元</div>
- </NButton>
- <NButton size="small" @click="openImportModal">导入商品销售渠道及价格</NButton>
- <NButton size="small" :disabled="tableData.length == 0" :loading="loading" @click="handleExport">
- 导出全部
- </NButton>
- <!-- <NButton size="small" :disabled="isDisabledExport">导出选中数据</NButton> -->
- <!-- <NButton size="small">修改记录</NButton> -->
- </NSpace>
- </template>
- </ZTable>
- <ZImportTemplate
- ref="importTemplateRef"
- url="/smqjh-pms/v1/videoProduct/exportTemplate"
- template-text="虚拟商品渠道及价格导入模版.xlsx"
- modal-text="导入虚拟商品销售渠道及价格"
- @submit="handleSubmitImport"
- ></ZImportTemplate>
- <BasicModal @register="registerModalPrice" @ok="handleSubmitPrice">
- <NDataTable :columns="PriceColumns" :data="PriceData" :row-key="row => row.channelId" />
- </BasicModal>
- <BasicModelForm @register-modal-form="registerModalForm" @submit-form="handleSubmit"></BasicModelForm>
- <BasicModelForm @register-modal-form="registerNameModalForm" @submit-form="handleSubmitName"></BasicModelForm>
- </LayoutTable>
- </template>
- <style scoped></style>
|