This commit is contained in:
2024-10-19 10:38:52 +08:00
parent 713f24ca3e
commit 00759864ed
75 changed files with 9465 additions and 2063 deletions

View File

@@ -2,7 +2,7 @@ VITE_APP_NAME=后台管理系统
VITE_SOCKET_URL=wss://server.gxwebsoft.com
VITE_SERVER_URL=https://server.gxwebsoft.com/api
VITE_THINK_URL=https://gxtyzx-api.websoft.top/api
#VITE_API_URL=https://modules.gxwebsoft.com/api
#VITE_API_URL=https://ngb-service-api.websoft.top/api
#VITE_SERVER_URL=http://127.0.0.1:9090/api

View File

@@ -2,4 +2,4 @@ VITE_APP_NAME=后台管理系统
VITE_SOCKET_URL=wss://server.gxwebsoft.com
VITE_SERVER_URL=https://server.gxwebsoft.com/api
VITE_THINK_URL=https://gxtyzx-api.websoft.top/api
VITE_API_URL=https://modules.gxwebsoft.com/api
VITE_API_URL=https://ngb-service-api.websoft.top/api

View File

@@ -18,6 +18,8 @@ export interface Article {
categoryName?: string;
// 封面图
image?: string;
imageWidth?: number;
imageHeight?: number;
// 附件
files?: string;
// 缩列图

View File

@@ -0,0 +1,106 @@
import request from '@/utils/request';
import type { ApiResult, PageResult } from '@/api';
import type { DesignCategory, DesignCategoryParam } from './model';
import { MODULES_API_URL } from '@/config/setting';
/**
* 分页查询设计征集报名分类
*/
export async function pageDesignCategory(params: DesignCategoryParam) {
const res = await request.get<ApiResult<PageResult<DesignCategory>>>(
MODULES_API_URL + '/cms/design-category/page',
{
params
}
);
if (res.data.code === 0) {
return res.data.data;
}
return Promise.reject(new Error(res.data.message));
}
/**
* 查询设计征集报名分类列表
*/
export async function listDesignCategory(params?: DesignCategoryParam) {
const res = await request.get<ApiResult<DesignCategory[]>>(
MODULES_API_URL + '/cms/design-category',
{
params
}
);
if (res.data.code === 0 && res.data.data) {
return res.data.data;
}
return Promise.reject(new Error(res.data.message));
}
/**
* 添加设计征集报名分类
*/
export async function addDesignCategory(data: DesignCategory) {
const res = await request.post<ApiResult<unknown>>(
MODULES_API_URL + '/cms/design-category',
data
);
if (res.data.code === 0) {
return res.data.message;
}
return Promise.reject(new Error(res.data.message));
}
/**
* 修改设计征集报名分类
*/
export async function updateDesignCategory(data: DesignCategory) {
const res = await request.put<ApiResult<unknown>>(
MODULES_API_URL + '/cms/design-category',
data
);
if (res.data.code === 0) {
return res.data.message;
}
return Promise.reject(new Error(res.data.message));
}
/**
* 删除设计征集报名分类
*/
export async function removeDesignCategory(id?: number) {
const res = await request.delete<ApiResult<unknown>>(
MODULES_API_URL + '/cms/design-category/' + id
);
if (res.data.code === 0) {
return res.data.message;
}
return Promise.reject(new Error(res.data.message));
}
/**
* 批量删除设计征集报名分类
*/
export async function removeBatchDesignCategory(data: (number | undefined)[]) {
const res = await request.delete<ApiResult<unknown>>(
MODULES_API_URL + '/cms/design-category/batch',
{
data
}
);
if (res.data.code === 0) {
return res.data.message;
}
return Promise.reject(new Error(res.data.message));
}
/**
* 根据id查询设计征集报名分类
*/
export async function getDesignCategory(id: number) {
const res = await request.get<ApiResult<DesignCategory>>(
MODULES_API_URL + '/cms/design-category/' + id
);
if (res.data.code === 0 && res.data.data) {
return res.data.data;
}
return Promise.reject(new Error(res.data.message));
}

View File

@@ -0,0 +1,35 @@
import type { PageParam } from '@/api';
/**
* 设计征集报名分类
*/
export interface DesignCategory {
//
id?: number;
//
title?: string;
// 用户ID
userId?: number;
// 排序(数字越小越靠前)
sortNumber?: number;
// 备注
comments?: string;
// 状态, 0已发布, 1待审核 2已驳回 3违规内容
status?: number;
// 是否删除, 0否, 1是
deleted?: number;
// 租户id
tenantId?: number;
// 创建时间
createTime?: string;
// 修改时间
updateTime?: string;
}
/**
* 设计征集报名分类搜索条件
*/
export interface DesignCategoryParam extends PageParam {
id?: number;
keywords?: string;
}

View File

@@ -0,0 +1,106 @@
import request from '@/utils/request';
import type { ApiResult, PageResult } from '@/api';
import type { DesignCollect, DesignCollectParam } from './model';
import { MODULES_API_URL } from '@/config/setting';
/**
* 分页查询设计征集
*/
export async function pageDesignCollect(params: DesignCollectParam) {
const res = await request.get<ApiResult<PageResult<DesignCollect>>>(
MODULES_API_URL + '/cms/design-collect/page',
{
params
}
);
if (res.data.code === 0) {
return res.data.data;
}
return Promise.reject(new Error(res.data.message));
}
/**
* 查询设计征集列表
*/
export async function listDesignCollect(params?: DesignCollectParam) {
const res = await request.get<ApiResult<DesignCollect[]>>(
MODULES_API_URL + '/cms/design-collect',
{
params
}
);
if (res.data.code === 0 && res.data.data) {
return res.data.data;
}
return Promise.reject(new Error(res.data.message));
}
/**
* 添加设计征集
*/
export async function addDesignCollect(data: DesignCollect) {
const res = await request.post<ApiResult<unknown>>(
MODULES_API_URL + '/cms/design-collect',
data
);
if (res.data.code === 0) {
return res.data.message;
}
return Promise.reject(new Error(res.data.message));
}
/**
* 修改设计征集
*/
export async function updateDesignCollect(data: DesignCollect) {
const res = await request.put<ApiResult<unknown>>(
MODULES_API_URL + '/cms/design-collect',
data
);
if (res.data.code === 0) {
return res.data.message;
}
return Promise.reject(new Error(res.data.message));
}
/**
* 删除设计征集
*/
export async function removeDesignCollect(id?: number) {
const res = await request.delete<ApiResult<unknown>>(
MODULES_API_URL + '/cms/design-collect/' + id
);
if (res.data.code === 0) {
return res.data.message;
}
return Promise.reject(new Error(res.data.message));
}
/**
* 批量删除设计征集
*/
export async function removeBatchDesignCollect(data: (number | undefined)[]) {
const res = await request.delete<ApiResult<unknown>>(
MODULES_API_URL + '/cms/design-collect/batch',
{
data
}
);
if (res.data.code === 0) {
return res.data.message;
}
return Promise.reject(new Error(res.data.message));
}
/**
* 根据id查询设计征集
*/
export async function getDesignCollect(id: number) {
const res = await request.get<ApiResult<DesignCollect>>(
MODULES_API_URL + '/cms/design-collect/' + id
);
if (res.data.code === 0 && res.data.data) {
return res.data.data;
}
return Promise.reject(new Error(res.data.message));
}

View File

@@ -0,0 +1,40 @@
import type { PageParam } from '@/api';
/**
* 设计征集
*/
export interface DesignCollect {
//
id?: number;
categoryId?: number;
//
title?: string;
//
content?: string;
//
image?: string;
// 用户ID
userId?: number;
// 排序(数字越小越靠前)
sortNumber?: number;
// 备注
comments?: string;
// 状态, 0已发布, 1待审核 2已驳回 3违规内容
status?: number;
// 是否删除, 0否, 1是
deleted?: number;
// 租户id
tenantId?: number;
// 创建时间
createTime?: string;
// 修改时间
updateTime?: string;
}
/**
* 设计征集搜索条件
*/
export interface DesignCollectParam extends PageParam {
id?: number;
keywords?: string;
}

View File

@@ -0,0 +1,106 @@
import request from '@/utils/request';
import type { ApiResult, PageResult } from '@/api';
import type { DesignSignUp, DesignSignUpParam } from './model';
import { MODULES_API_URL } from '@/config/setting';
/**
* 分页查询设计征集报名
*/
export async function pageDesignSignUp(params: DesignSignUpParam) {
const res = await request.get<ApiResult<PageResult<DesignSignUp>>>(
MODULES_API_URL + '/cms/design-sign-up/page',
{
params
}
);
if (res.data.code === 0) {
return res.data.data;
}
return Promise.reject(new Error(res.data.message));
}
/**
* 查询设计征集报名列表
*/
export async function listDesignSignUp(params?: DesignSignUpParam) {
const res = await request.get<ApiResult<DesignSignUp[]>>(
MODULES_API_URL + '/cms/design-sign-up',
{
params
}
);
if (res.data.code === 0 && res.data.data) {
return res.data.data;
}
return Promise.reject(new Error(res.data.message));
}
/**
* 添加设计征集报名
*/
export async function addDesignSignUp(data: DesignSignUp) {
const res = await request.post<ApiResult<unknown>>(
MODULES_API_URL + '/cms/design-sign-up',
data
);
if (res.data.code === 0) {
return res.data.message;
}
return Promise.reject(new Error(res.data.message));
}
/**
* 修改设计征集报名
*/
export async function updateDesignSignUp(data: DesignSignUp) {
const res = await request.put<ApiResult<unknown>>(
MODULES_API_URL + '/cms/design-sign-up',
data
);
if (res.data.code === 0) {
return res.data.message;
}
return Promise.reject(new Error(res.data.message));
}
/**
* 删除设计征集报名
*/
export async function removeDesignSignUp(id?: number) {
const res = await request.delete<ApiResult<unknown>>(
MODULES_API_URL + '/cms/design-sign-up/' + id
);
if (res.data.code === 0) {
return res.data.message;
}
return Promise.reject(new Error(res.data.message));
}
/**
* 批量删除设计征集报名
*/
export async function removeBatchDesignSignUp(data: (number | undefined)[]) {
const res = await request.delete<ApiResult<unknown>>(
MODULES_API_URL + '/cms/design-sign-up/batch',
{
data
}
);
if (res.data.code === 0) {
return res.data.message;
}
return Promise.reject(new Error(res.data.message));
}
/**
* 根据id查询设计征集报名
*/
export async function getDesignSignUp(id: number) {
const res = await request.get<ApiResult<DesignSignUp>>(
MODULES_API_URL + '/cms/design-sign-up/' + id
);
if (res.data.code === 0 && res.data.data) {
return res.data.data;
}
return Promise.reject(new Error(res.data.message));
}

View File

@@ -0,0 +1,42 @@
import type {PageParam} from '@/api';
/**
* 设计征集报名
*/
export interface DesignSignUp {
//
id?: number;
//
designId?: number;
//
name?: string;
//
phone?: string;
//
content?: string;
// 用户ID
userId?: number;
// 排序(数字越小越靠前)
sortNumber?: number;
// 备注
comments?: string;
// 状态, 0已发布, 1待审核 2已驳回 3违规内容
status?: number;
// 是否删除, 0否, 1是
deleted?: number;
// 租户id
tenantId?: number;
// 创建时间
createTime?: string;
// 修改时间
updateTime?: string;
}
/**
* 设计征集报名搜索条件
*/
export interface DesignSignUpParam extends PageParam {
id?: number;
designId?: number;
keywords?: string;
}

View File

@@ -0,0 +1,231 @@
import request from '@/utils/request';
import type { ApiResult, PageResult } from '@/api';
<<<<<<< HEAD
=======
<<<<<<< HEAD:modules/api/booking_____/order/index.ts
import type { Order, OrderParam } from './model';
import { MODULES_API_URL } from '@/config/setting';
/**
* 分页查询
*/
export async function pageOrder(params: OrderParam) {
const res = await request.get<ApiResult<PageResult<Order>>>(
MODULES_API_URL + '/booking/order/page',
=======
>>>>>>> origin/master
import type { Count, CountParam } from './model';
import { MODULES_API_URL } from '@/config/setting';
export async function data(params: CountParam) {
const res = await request.get<ApiResult<Count[]>>(
MODULES_API_URL + '/shop/count/data',
<<<<<<< HEAD
=======
>>>>>>> origin/master:src/api/shop/count/index.ts
>>>>>>> origin/master
{
params
}
);
if (res.data.code === 0) {
return res.data.data;
}
return Promise.reject(new Error(res.data.message));
}
/**
<<<<<<< HEAD
=======
<<<<<<< HEAD:modules/api/booking_____/order/index.ts
* 查询列表
*/
export async function listOrder(params?: OrderParam) {
const res = await request.get<ApiResult<Order[]>>(
MODULES_API_URL + '/booking/order',
=======
>>>>>>> origin/master
* 分页查询商城销售统计表
*/
export async function pageCount(params: CountParam) {
const res = await request.get<ApiResult<PageResult<Count>>>(
MODULES_API_URL + '/shop/count/page',
<<<<<<< HEAD
=======
>>>>>>> origin/master:src/api/shop/count/index.ts
>>>>>>> origin/master
{
params
}
);
if (res.data.code === 0) {
return res.data.data;
}
return Promise.reject(new Error(res.data.message));
}
/**
<<<<<<< HEAD
=======
<<<<<<< HEAD:modules/api/booking_____/order/index.ts
* 添加
=======
>>>>>>> origin/master
* 查询商城销售统计表列表
*/
export async function listCount(params?: CountParam) {
const res = await request.get<ApiResult<Count[]>>(
MODULES_API_URL + '/shop/count',
{
params
}
);
if (res.data.code === 0 && res.data.data) {
return res.data.data;
}
return Promise.reject(new Error(res.data.message));
}
/**
* 添加商城销售统计表
<<<<<<< HEAD
*/
export async function addCount(data: Count) {
const res = await request.post<ApiResult<unknown>>(
MODULES_API_URL + '/shop/count',
=======
>>>>>>> origin/master:src/api/shop/count/index.ts
*/
export async function addCount(data: Count) {
const res = await request.post<ApiResult<unknown>>(
<<<<<<< HEAD:modules/api/booking_____/order/index.ts
MODULES_API_URL + '/booking/order',
=======
MODULES_API_URL + '/shop/count',
>>>>>>> origin/master:src/api/shop/count/index.ts
>>>>>>> origin/master
data
);
if (res.data.code === 0) {
return res.data.message;
}
return Promise.reject(new Error(res.data.message));
}
/**
<<<<<<< HEAD
* 修改商城销售统计表
*/
export async function updateCount(data: Count) {
const res = await request.put<ApiResult<unknown>>(
MODULES_API_URL + '/shop/count',
=======
<<<<<<< HEAD:modules/api/booking_____/order/index.ts
* 修改
=======
* 修改商城销售统计表
>>>>>>> origin/master:src/api/shop/count/index.ts
*/
export async function updateCount(data: Count) {
const res = await request.put<ApiResult<unknown>>(
<<<<<<< HEAD:modules/api/booking_____/order/index.ts
MODULES_API_URL + '/booking/order',
=======
MODULES_API_URL + '/shop/count',
>>>>>>> origin/master:src/api/shop/count/index.ts
>>>>>>> origin/master
data
);
if (res.data.code === 0) {
return res.data.message;
}
return Promise.reject(new Error(res.data.message));
}
/**
<<<<<<< HEAD
* 删除商城销售统计表
*/
export async function removeCount(id?: number) {
const res = await request.delete<ApiResult<unknown>>(
MODULES_API_URL + '/shop/count/' + id
=======
<<<<<<< HEAD:modules/api/booking_____/order/index.ts
* 删除
=======
* 删除商城销售统计表
>>>>>>> origin/master:src/api/shop/count/index.ts
*/
export async function removeCount(id?: number) {
const res = await request.delete<ApiResult<unknown>>(
<<<<<<< HEAD:modules/api/booking_____/order/index.ts
MODULES_API_URL + '/booking/order/' + id
=======
MODULES_API_URL + '/shop/count/' + id
>>>>>>> origin/master:src/api/shop/count/index.ts
>>>>>>> origin/master
);
if (res.data.code === 0) {
return res.data.message;
}
return Promise.reject(new Error(res.data.message));
}
/**
<<<<<<< HEAD
* 批量删除商城销售统计表
*/
export async function removeBatchCount(data: (number | undefined)[]) {
const res = await request.delete<ApiResult<unknown>>(
MODULES_API_URL + '/shop/count/batch',
=======
<<<<<<< HEAD:modules/api/booking_____/order/index.ts
* 批量删除
=======
* 批量删除商城销售统计表
>>>>>>> origin/master:src/api/shop/count/index.ts
*/
export async function removeBatchCount(data: (number | undefined)[]) {
const res = await request.delete<ApiResult<unknown>>(
<<<<<<< HEAD:modules/api/booking_____/order/index.ts
MODULES_API_URL + '/booking/order/batch',
=======
MODULES_API_URL + '/shop/count/batch',
>>>>>>> origin/master:src/api/shop/count/index.ts
>>>>>>> origin/master
{
data
}
);
if (res.data.code === 0) {
return res.data.message;
}
return Promise.reject(new Error(res.data.message));
}
/**
<<<<<<< HEAD
=======
<<<<<<< HEAD:modules/api/booking_____/order/index.ts
* 根据id查询
*/
export async function getOrder(id: number) {
const res = await request.get<ApiResult<Order>>(
MODULES_API_URL + '/booking/order/' + id
=======
>>>>>>> origin/master
* 根据id查询商城销售统计表
*/
export async function getCount(id: number) {
const res = await request.get<ApiResult<Count>>(
MODULES_API_URL + '/shop/count/' + id
<<<<<<< HEAD
=======
>>>>>>> origin/master:src/api/shop/count/index.ts
>>>>>>> origin/master
);
if (res.data.code === 0 && res.data.data) {
return res.data.data;
}
return Promise.reject(new Error(res.data.message));
}

View File

@@ -45,18 +45,30 @@ export interface Goods {
price?: string;
// 销售价格
salePrice?: string;
// 有赠品
priceGift?: boolean;
chainStorePrice?: string;
chainStoreRate?: string;
memberStoreRate?: string;
memberMarketRate?: string;
memberStorePrice?: string;
memberMarketPrice?: string;
// 经销商价格
dealerPrice?: string;
// 有赠品
dealerGift?: string;
buyingGift?: boolean;
// 有赠品
priceGift?: boolean;
// 有赠品
dealerGift?: boolean;
buyingGiftNum?: number;
priceGiftNum?: number;
dealerGiftNum?: number;
// 库存计算方式(10下单减库存 20付款减库存)
deductStockType?: number;
// 封面图
files?: string;
// 销量
sales?: number;
isNew?: number;
// 库存
stock?: number;
// 商品重量
@@ -69,6 +81,8 @@ export interface Goods {
merchantId?: number;
// 商户名称
merchantName?: string;
supplierMerchantId?: number;
supplierName?: string;
// 状态0未上架1上架
isShow?: number;
// 状态, 0上架 1待上架 2待审核 3审核不通过

View File

@@ -0,0 +1,106 @@
import request from '@/utils/request';
import type { ApiResult, PageResult } from '@/api';
import type { GoodsIncomeConfig, GoodsIncomeConfigParam } from './model';
import { MODULES_API_URL } from '@/config/setting';
/**
* 分页查询分润配置
*/
export async function pageGoodsIncomeConfig(params: GoodsIncomeConfigParam) {
const res = await request.get<ApiResult<PageResult<GoodsIncomeConfig>>>(
MODULES_API_URL + '/shop/goods-income-config/page',
{
params
}
);
if (res.data.code === 0) {
return res.data.data;
}
return Promise.reject(new Error(res.data.message));
}
/**
* 查询分润配置列表
*/
export async function listGoodsIncomeConfig(params?: GoodsIncomeConfigParam) {
const res = await request.get<ApiResult<GoodsIncomeConfig[]>>(
MODULES_API_URL + '/shop/goods-income-config',
{
params
}
);
if (res.data.code === 0 && res.data.data) {
return res.data.data;
}
return Promise.reject(new Error(res.data.message));
}
/**
* 添加分润配置
*/
export async function addGoodsIncomeConfig(data: GoodsIncomeConfig) {
const res = await request.post<ApiResult<unknown>>(
MODULES_API_URL + '/shop/goods-income-config',
data
);
if (res.data.code === 0) {
return res.data.message;
}
return Promise.reject(new Error(res.data.message));
}
/**
* 修改分润配置
*/
export async function updateGoodsIncomeConfig(data: GoodsIncomeConfig) {
const res = await request.put<ApiResult<unknown>>(
MODULES_API_URL + '/shop/goods-income-config',
data
);
if (res.data.code === 0) {
return res.data.message;
}
return Promise.reject(new Error(res.data.message));
}
/**
* 删除分润配置
*/
export async function removeGoodsIncomeConfig(id?: number) {
const res = await request.delete<ApiResult<unknown>>(
MODULES_API_URL + '/shop/goods-income-config/' + id
);
if (res.data.code === 0) {
return res.data.message;
}
return Promise.reject(new Error(res.data.message));
}
/**
* 批量删除分润配置
*/
export async function removeBatchGoodsIncomeConfig(data: (number | undefined)[]) {
const res = await request.delete<ApiResult<unknown>>(
MODULES_API_URL + '/shop/goods-income-config/batch',
{
data
}
);
if (res.data.code === 0) {
return res.data.message;
}
return Promise.reject(new Error(res.data.message));
}
/**
* 根据id查询分润配置
*/
export async function getGoodsIncomeConfig(id: number) {
const res = await request.get<ApiResult<GoodsIncomeConfig>>(
MODULES_API_URL + '/shop/goods-income-config/' + id
);
if (res.data.code === 0 && res.data.data) {
return res.data.data;
}
return Promise.reject(new Error(res.data.message));
}

View File

@@ -0,0 +1,39 @@
import type { PageParam } from '@/api';
/**
* 分润配置
*/
export interface GoodsIncomeConfig {
//
id?: number;
//
goodsId?: number;
// 店铺类型
merchantShopType?: string;
//
skuId?: number;
// 比例
rate?: string;
// 用户id
userId?: number;
// 备注
comments?: string;
// 排序号
sortNumber?: number;
// 是否删除, 0否, 1是
deleted?: number;
// 租户id
tenantId?: number;
// 修改时间
updateTime?: string;
// 创建时间
createTime?: string;
}
/**
* 分润配置搜索条件
*/
export interface GoodsIncomeConfigParam extends PageParam {
id?: number;
keywords?: string;
}

View File

@@ -0,0 +1,106 @@
import request from '@/utils/request';
import type { ApiResult, PageResult } from '@/api';
import type { GoodsStockInMerchant, GoodsStockInMerchantParam } from './model';
import { MODULES_API_URL } from '@/config/setting';
/**
* 分页查询商户商品库存
*/
export async function pageGoodsStockInMerchant(params: GoodsStockInMerchantParam) {
const res = await request.get<ApiResult<PageResult<GoodsStockInMerchant>>>(
MODULES_API_URL + '/shop/goods-stock-in-merchant/page',
{
params
}
);
if (res.data.code === 0) {
return res.data.data;
}
return Promise.reject(new Error(res.data.message));
}
/**
* 查询商户商品库存列表
*/
export async function listGoodsStockInMerchant(params?: GoodsStockInMerchantParam) {
const res = await request.get<ApiResult<GoodsStockInMerchant[]>>(
MODULES_API_URL + '/shop/goods-stock-in-merchant',
{
params
}
);
if (res.data.code === 0 && res.data.data) {
return res.data.data;
}
return Promise.reject(new Error(res.data.message));
}
/**
* 添加商户商品库存
*/
export async function addGoodsStockInMerchant(data: GoodsStockInMerchant) {
const res = await request.post<ApiResult<unknown>>(
MODULES_API_URL + '/shop/goods-stock-in-merchant',
data
);
if (res.data.code === 0) {
return res.data.message;
}
return Promise.reject(new Error(res.data.message));
}
/**
* 修改商户商品库存
*/
export async function updateGoodsStockInMerchant(data: GoodsStockInMerchant) {
const res = await request.put<ApiResult<unknown>>(
MODULES_API_URL + '/shop/goods-stock-in-merchant',
data
);
if (res.data.code === 0) {
return res.data.message;
}
return Promise.reject(new Error(res.data.message));
}
/**
* 删除商户商品库存
*/
export async function removeGoodsStockInMerchant(id?: number) {
const res = await request.delete<ApiResult<unknown>>(
MODULES_API_URL + '/shop/goods-stock-in-merchant/' + id
);
if (res.data.code === 0) {
return res.data.message;
}
return Promise.reject(new Error(res.data.message));
}
/**
* 批量删除商户商品库存
*/
export async function removeBatchGoodsStockInMerchant(data: (number | undefined)[]) {
const res = await request.delete<ApiResult<unknown>>(
MODULES_API_URL + '/shop/goods-stock-in-merchant/batch',
{
data
}
);
if (res.data.code === 0) {
return res.data.message;
}
return Promise.reject(new Error(res.data.message));
}
/**
* 根据id查询商户商品库存
*/
export async function getGoodsStockInMerchant(id: number) {
const res = await request.get<ApiResult<GoodsStockInMerchant>>(
MODULES_API_URL + '/shop/goods-stock-in-merchant/' + id
);
if (res.data.code === 0 && res.data.data) {
return res.data.data;
}
return Promise.reject(new Error(res.data.message));
}

View File

@@ -0,0 +1,43 @@
import type { PageParam } from '@/api';
/**
* 商户商品库存
*/
export interface GoodsStockInMerchant {
//
id?: number;
//
goodsId?: number;
//
skuId?: number;
//
num?: number;
//
merchantId?: number;
//
stock?: number;
// 状态, 0上架 1待上架 2待审核 3审核不通过
status?: number;
// 备注
comments?: string;
// 排序号
sortNumber?: number;
// 用户ID
userId?: number;
// 是否删除, 0否, 1是
deleted?: number;
// 租户id
tenantId?: number;
// 创建时间
createTime?: string;
// 修改时间
updateTime?: string;
}
/**
* 商户商品库存搜索条件
*/
export interface GoodsStockInMerchantParam extends PageParam {
id?: number;
keywords?: string;
}

View File

@@ -53,12 +53,16 @@ export interface Merchant {
ownStore?: number;
// 是否推荐
recommend?: number;
taxRate?: number;
// 是否需要审核
goodsReview?: number;
// 管理入口
adminUrl?: string;
// 备注
comments?: string;
startTime?: string;
endTime?: string;
isOn?: number;
// 状态
status?: number;
// 排序号

View File

@@ -1,6 +1,8 @@
import type { PageParam } from '@/api';
import { ShopOrderGoods } from '@/api/shop/shopOrderGoods/model';
import { OrderInfo } from '@/api/shop/orderInfo/model';
import {OrderDelivery} from "@/api/shop/orderDelivery/model";
import {OrderGoods} from "@/api/shop/orderGoods/model";
import {Merchant} from "@/api/shop/merchant/model";
/**
*
@@ -63,11 +65,11 @@ export interface Order {
// 教练id
coachId?: number;
// 1微信支付2积分3支付宝4现金5POS机6VIP月卡7VIP年卡8VIP次卡9IC月卡10IC年卡11IC次卡12免费13VIP充值卡14IC充值卡15积分支付16VIP季卡17IC季卡
payType?: string;
payType?: number;
// 1已付款2未付款
payStatus?: string;
payStatus?: number;
// 1已完成2未使用3已取消4退款申请中5退款被拒绝6退款成功7客户端申请退款
orderStatus?: string;
orderStatus?: number;
// 优惠类型0无、1抵扣优惠券、2折扣优惠券、3、VIP月卡、4VIP年卡5VIP次卡、6VIP会员卡、7IC月卡、8IC年卡、9IC次卡、10IC会员卡、11免费订单、12VIP充值卡、13IC充值卡、14VIP季卡、15IC季卡
couponType?: string;
// 二维码地址,保存订单号,支付成功后才生成
@@ -88,6 +90,7 @@ export interface Order {
updateTime?: number;
// 付款时间
payTime?: number;
deliveryType?: number;
// 退款时间
refundTime?: number;
// 申请退款时间
@@ -106,8 +109,18 @@ export interface Order {
deleted?: number;
// 租户id
tenantId?: number;
selfTakeMerchantId?: number;
selfTakeMerchantName?: string;
expressMerchantId?: number;
expressMerchantName?: string;
sendStartTime?: string;
sendEndTime?: string;
hasTakeGift?: number;
selfTakeMerchant?: Merchant;
merchant?: Merchant;
orderInfo?: OrderInfo[];
orderGoods?: ShopOrderGoods[];
orderGoods?: OrderGoods[];
orderDelivery?: OrderDelivery
}
/**

View File

@@ -0,0 +1,19 @@
import request from '@/utils/request';
import type { ApiResult } from '@/api';
import { MODULES_API_URL } from '@/config/setting';
import {OrderDelivery} from "@/api/shop/orderDelivery/model";
/**
* 添加
*/
export async function addOrderDelivery(data: OrderDelivery) {
const res = await request.post<ApiResult<unknown>>(
MODULES_API_URL + '/shop/order-delivery',
data
);
if (res.data.code === 0) {
return res.data.message;
}
return Promise.reject(new Error(res.data.message));
}

View File

@@ -0,0 +1,27 @@
import type { PageParam } from '@/api';
import {Express} from "@/api/shop/express/model";
/**
*
*/
export interface OrderDelivery {
//
deliveryId?: number;
orderId?: number;
deliveryMethod?: number;
expressId?: number;
expressNo?: string;
eorderHtml?: string;
// 创建时间
createTime?: string;
express?: Express;
}
/**
* 搜索条件
*/
export interface OrderDeliveryParam extends PageParam {
id?: number;
oid?: number;
keywords?: string;
}

View File

@@ -0,0 +1,106 @@
import request from '@/utils/request';
import type { ApiResult, PageResult } from '@/api';
import type { Splash, SplashParam } from './model';
import { MODULES_API_URL } from '@/config/setting';
/**
* 分页查询开屏广告
*/
export async function pageSplash(params: SplashParam) {
const res = await request.get<ApiResult<PageResult<Splash>>>(
MODULES_API_URL + '/shop/splash/page',
{
params
}
);
if (res.data.code === 0) {
return res.data.data;
}
return Promise.reject(new Error(res.data.message));
}
/**
* 查询开屏广告列表
*/
export async function listSplash(params?: SplashParam) {
const res = await request.get<ApiResult<Splash[]>>(
MODULES_API_URL + '/shop/splash',
{
params
}
);
if (res.data.code === 0 && res.data.data) {
return res.data.data;
}
return Promise.reject(new Error(res.data.message));
}
/**
* 添加开屏广告
*/
export async function addSplash(data: Splash) {
const res = await request.post<ApiResult<unknown>>(
MODULES_API_URL + '/shop/splash',
data
);
if (res.data.code === 0) {
return res.data.message;
}
return Promise.reject(new Error(res.data.message));
}
/**
* 修改开屏广告
*/
export async function updateSplash(data: Splash) {
const res = await request.put<ApiResult<unknown>>(
MODULES_API_URL + '/shop/splash',
data
);
if (res.data.code === 0) {
return res.data.message;
}
return Promise.reject(new Error(res.data.message));
}
/**
* 删除开屏广告
*/
export async function removeSplash(id?: number) {
const res = await request.delete<ApiResult<unknown>>(
MODULES_API_URL + '/shop/splash/' + id
);
if (res.data.code === 0) {
return res.data.message;
}
return Promise.reject(new Error(res.data.message));
}
/**
* 批量删除开屏广告
*/
export async function removeBatchSplash(data: (number | undefined)[]) {
const res = await request.delete<ApiResult<unknown>>(
MODULES_API_URL + '/shop/splash/batch',
{
data
}
);
if (res.data.code === 0) {
return res.data.message;
}
return Promise.reject(new Error(res.data.message));
}
/**
* 根据id查询开屏广告
*/
export async function getSplash(id: number) {
const res = await request.get<ApiResult<Splash>>(
MODULES_API_URL + '/shop/splash/' + id
);
if (res.data.code === 0 && res.data.data) {
return res.data.data;
}
return Promise.reject(new Error(res.data.message));
}

View File

@@ -0,0 +1,50 @@
import type {PageParam} from '@/api';
/**
* 开屏广告
*/
export interface Splash {
//
id?: number;
// 标题
title?: string;
// 图片
image?: string;
// 跳转类型
jumpType?: string;
// 跳转主键
jumpPk?: number;
// 备注
comments?: string;
// 排序号
sortNumber?: number;
// 用户ID
userId?: number;
// 是否删除, 0否, 1是
deleted?: number;
// 租户id
tenantId?: number;
// 创建时间
createTime?: string;
// 修改时间
updateTime?: string;
}
/**
* 开屏广告搜索条件
*/
export interface SplashParam extends PageParam {
id?: number;
keywords?: string;
}
export const SplashJumpType = [
{
label: '商品',
value: 'goods'
},
{
label: '店铺',
value: 'merchant'
}
]

View File

@@ -0,0 +1,106 @@
import request from '@/utils/request';
import type { ApiResult, PageResult } from '@/api';
import type { Swiper, SwiperParam } from './model';
import { MODULES_API_URL } from '@/config/setting';
/**
* 分页查询轮播图
*/
export async function pageSwiper(params: SwiperParam) {
const res = await request.get<ApiResult<PageResult<Swiper>>>(
MODULES_API_URL + '/shop/swiper/page',
{
params
}
);
if (res.data.code === 0) {
return res.data.data;
}
return Promise.reject(new Error(res.data.message));
}
/**
* 查询轮播图列表
*/
export async function listSwiper(params?: SwiperParam) {
const res = await request.get<ApiResult<Swiper[]>>(
MODULES_API_URL + '/shop/swiper',
{
params
}
);
if (res.data.code === 0 && res.data.data) {
return res.data.data;
}
return Promise.reject(new Error(res.data.message));
}
/**
* 添加轮播图
*/
export async function addSwiper(data: Swiper) {
const res = await request.post<ApiResult<unknown>>(
MODULES_API_URL + '/shop/swiper',
data
);
if (res.data.code === 0) {
return res.data.message;
}
return Promise.reject(new Error(res.data.message));
}
/**
* 修改轮播图
*/
export async function updateSwiper(data: Swiper) {
const res = await request.put<ApiResult<unknown>>(
MODULES_API_URL + '/shop/swiper',
data
);
if (res.data.code === 0) {
return res.data.message;
}
return Promise.reject(new Error(res.data.message));
}
/**
* 删除轮播图
*/
export async function removeSwiper(id?: number) {
const res = await request.delete<ApiResult<unknown>>(
MODULES_API_URL + '/shop/swiper/' + id
);
if (res.data.code === 0) {
return res.data.message;
}
return Promise.reject(new Error(res.data.message));
}
/**
* 批量删除轮播图
*/
export async function removeBatchSwiper(data: (number | undefined)[]) {
const res = await request.delete<ApiResult<unknown>>(
MODULES_API_URL + '/shop/swiper/batch',
{
data
}
);
if (res.data.code === 0) {
return res.data.message;
}
return Promise.reject(new Error(res.data.message));
}
/**
* 根据id查询轮播图
*/
export async function getSwiper(id: number) {
const res = await request.get<ApiResult<Swiper>>(
MODULES_API_URL + '/shop/swiper/' + id
);
if (res.data.code === 0 && res.data.data) {
return res.data.data;
}
return Promise.reject(new Error(res.data.message));
}

View File

@@ -0,0 +1,79 @@
import type { PageParam } from '@/api';
/**
* 轮播图
*/
export interface Swiper {
//
id?: number;
// 所属页面
type?: string;
// 图片
image?: string;
// 跳转类型
jumpType?: string;
// 跳转主键
jumpPk?: number;
// 备注
comments?: string;
color?: string;
// 排序号
sortNumber?: number;
// 用户ID
userId?: number;
// 是否删除, 0否, 1是
deleted?: number;
// 租户id
tenantId?: number;
// 创建时间
createTime?: string;
// 修改时间
updateTime?: string;
}
/**
* 轮播图搜索条件
*/
export interface SwiperParam extends PageParam {
id?: number;
keywords?: string;
}
export const SwiperType = [
{
label: '会员商城',
value: '会员商城'
},
{
label: '会员店',
value: '会员店'
},
{
label: '实体连锁店',
value: '实体连锁店'
},
{
label: '会员超市',
value: '会员超市'
},
{
label: '物流配送',
value: '物流配送'
},
{
label: '设计征集',
value: '设计征集'
},
{
label: '招商',
value: '招商'
},
]
export const SwiperJumpType = [
{
label: '商品',
value: 'goods'
}
]

View File

@@ -0,0 +1,106 @@
import request from '@/utils/request';
import type { ApiResult, PageResult } from '@/api';
import type { UserCollection, UserCollectionParam } from './model';
import { MODULES_API_URL } from '@/config/setting';
/**
* 分页查询我的收藏
*/
export async function pageUserCollection(params: UserCollectionParam) {
const res = await request.get<ApiResult<PageResult<UserCollection>>>(
MODULES_API_URL + '/shop/user-collection/page',
{
params
}
);
if (res.data.code === 0) {
return res.data.data;
}
return Promise.reject(new Error(res.data.message));
}
/**
* 查询我的收藏列表
*/
export async function listUserCollection(params?: UserCollectionParam) {
const res = await request.get<ApiResult<UserCollection[]>>(
MODULES_API_URL + '/shop/user-collection',
{
params
}
);
if (res.data.code === 0 && res.data.data) {
return res.data.data;
}
return Promise.reject(new Error(res.data.message));
}
/**
* 添加我的收藏
*/
export async function addUserCollection(data: UserCollection) {
const res = await request.post<ApiResult<unknown>>(
MODULES_API_URL + '/shop/user-collection',
data
);
if (res.data.code === 0) {
return res.data.message;
}
return Promise.reject(new Error(res.data.message));
}
/**
* 修改我的收藏
*/
export async function updateUserCollection(data: UserCollection) {
const res = await request.put<ApiResult<unknown>>(
MODULES_API_URL + '/shop/user-collection',
data
);
if (res.data.code === 0) {
return res.data.message;
}
return Promise.reject(new Error(res.data.message));
}
/**
* 删除我的收藏
*/
export async function removeUserCollection(id?: number) {
const res = await request.delete<ApiResult<unknown>>(
MODULES_API_URL + '/shop/user-collection/' + id
);
if (res.data.code === 0) {
return res.data.message;
}
return Promise.reject(new Error(res.data.message));
}
/**
* 批量删除我的收藏
*/
export async function removeBatchUserCollection(data: (number | undefined)[]) {
const res = await request.delete<ApiResult<unknown>>(
MODULES_API_URL + '/shop/user-collection/batch',
{
data
}
);
if (res.data.code === 0) {
return res.data.message;
}
return Promise.reject(new Error(res.data.message));
}
/**
* 根据id查询我的收藏
*/
export async function getUserCollection(id: number) {
const res = await request.get<ApiResult<UserCollection>>(
MODULES_API_URL + '/shop/user-collection/' + id
);
if (res.data.code === 0 && res.data.data) {
return res.data.data;
}
return Promise.reject(new Error(res.data.message));
}

View File

@@ -0,0 +1,27 @@
import type { PageParam } from '@/api';
/**
* 我的收藏
*/
export interface UserCollection {
// 主键ID
id?: number;
// 0店铺1商品
type?: string;
// 租户ID
tid?: number;
// 用户ID
userId?: number;
// 租户id
tenantId?: number;
// 注册时间
createTime?: string;
}
/**
* 我的收藏搜索条件
*/
export interface UserCollectionParam extends PageParam {
id?: number;
keywords?: string;
}

View File

@@ -60,6 +60,12 @@
label: '现金支付',
key: 'cashPayment',
icon: 'PayCircleOutlined'
},
{
value: 16,
label: '代付',
key: 'friendPayment',
icon: 'https://oss.wsdns.cn/20241002/3fe17586c7394a1290fd0dae03eb1f24.png'
}
]);

View File

@@ -108,6 +108,7 @@
</template>
<!-- 含http -->
<template v-else-if="record.path.indexOf('http') == 0">
<div class="bg-gray-300">
<a-image
:src="`${record.path}`"
:preview="{
@@ -115,6 +116,7 @@
}"
:width="100"
/>
</div>
</template>
<!-- path -->
<template v-else>

View File

@@ -3,12 +3,20 @@
align-items: center;
justify-content: flex-start;flex-wrap: wrap">
<template v-for="(item, index) in data" :key="index">
<video v-if="type === 'video'" :src="item.url" style="width: 400px; height: 200px" controls="controls"></video>
<div v-if="type === 'video' || item.url.includes('.mp4')" class="relative cursor-pointer" @click="open(item.url)">
<img
:src="item.url + '?x-oss-process=video/snapshot,t_2000,f_jpg,w_200,h_200'"
style="width: 80px; height: 80px"
/>
<div class="absolute" style="left: 30px; top: 30px">
<play-circle-outlined style="font-size: 20px; color:white"/>
</div>
</div>
<a-tag :key="item.url" closable @close="onDeleteItem(index)"
@click.native="open(item.url)" style="cursor: pointer"
v-else-if="type && ['audio', 'file'].includes(type)"> {{ item.url }}
</a-tag>
<div class="image-upload-item" v-else>
<div class="image-upload-item bg-gray-300" v-else>
<a-image-preview-group>
<a-image
:width="width"
@@ -57,7 +65,7 @@
</template>
<script lang="ts" setup>
import {PlusOutlined, CloseOutlined} from '@ant-design/icons-vue';
import {PlusOutlined, CloseOutlined, PlayCircleOutlined} from '@ant-design/icons-vue';
import {ref} from 'vue';
import SelectData from './components/select-data.vue';
import {FileRecord} from '@/api/system/file/model';

View File

@@ -64,6 +64,7 @@
title?: string;
// 商户类型
shopType?: string;
type?: string;
// 修改回显的数据
data?: Merchant | null;
}>();
@@ -99,7 +100,7 @@
{
title: '商户类型',
dataIndex: 'shopType',
key: 'shopType'
// key: 'shopType'
},
{
title: '操作',
@@ -120,6 +121,9 @@
} else {
where.shopType = props.shopType;
}
if (props.type) {
where.type = props.type;
}
return pageMerchant({
...where,
...orders,

View File

@@ -17,6 +17,7 @@
:data="current"
:title="placeholder"
:customer-type="customerType"
:shopType="shopType"
@done="onChange"
/>
</div>
@@ -33,6 +34,7 @@
value?: any;
customerType?: string;
placeholder?: string;
shopType?: string;
}>(),
{
placeholder: '请选择商户'

View File

@@ -355,6 +355,7 @@ watch(
status: 'done'
});
});
console.log(images.value)
}
// if (props.data.adType == '幻灯片') {
// const arr = JSON.parse(props.data.path);

View File

@@ -42,7 +42,7 @@
v-model:value="form.title"
/>
</a-form-item>
<a-form-item label="文章图片" name="image">
<a-form-item label="文章图片/视频" name="image">
<SelectFile
:placeholder="`请选择图片`"
:limit="1"
@@ -137,8 +137,6 @@
import { listArticleCategory } from "@/api/cms/category";
import { Navigation } from "@/api/cms/navigation/model";
import SourceSelect from "@/views/cms/article/dictionary/source-select.vue";
import { getCmsArticleContent } from "@/api/cms/cmsArticleContent";
import { isImage } from "@/utils/common";
import { getMerchantId } from "@/utils/merchant";
// 是否是修改
@@ -289,6 +287,7 @@
});
const chooseImage = (data: FileRecord) => {
console.log(data)
images.value.push({
uid: data.id,
url: data.path,

View File

@@ -0,0 +1,142 @@
<!-- 编辑弹窗 -->
<template>
<ele-modal
:width="800"
:visible="visible"
:maskClosable="false"
:maxable="maxable"
:title="isUpdate ? '编辑设计征集报名分类' : '添加设计征集报名分类'"
:body-style="{ paddingBottom: '28px' }"
@update:visible="updateVisible"
@ok="save"
>
<a-form
ref="formRef"
:model="form"
:rules="rules"
:label-col="styleResponsive ? { md: 4, sm: 5, xs: 24 } : { flex: '90px' }"
:wrapper-col="
styleResponsive ? { md: 19, sm: 19, xs: 24 } : { flex: '1' }
"
>
<a-form-item label="标题" name="title">
<a-input
allow-clear
placeholder="请输入标题"
v-model:value="form.title"
/>
</a-form-item>
</a-form>
</ele-modal>
</template>
<script lang="ts" setup>
import {ref, reactive, watch} from 'vue';
import {Form, message} from 'ant-design-vue';
import {assignObject, uuid} from 'ele-admin-pro';
import {addDesignCategory, updateDesignCategory} from '@/api/cms/designCategory';
import {DesignCategory} from '@/api/cms/designCategory/model';
import {useThemeStore} from '@/store/modules/theme';
import {storeToRefs} from 'pinia';
import {ItemType} from 'ele-admin-pro/es/ele-image-upload/types';
import {FormInstance} from 'ant-design-vue/es/form';
// 是否是修改
const isUpdate = ref(false);
const useForm = Form.useForm;
// 是否开启响应式布局
const themeStore = useThemeStore();
const {styleResponsive} = storeToRefs(themeStore);
const props = defineProps<{
// 弹窗是否打开
visible: boolean;
// 修改回显的数据
data?: DesignCategory | null;
}>();
const emit = defineEmits<{
(e: 'done'): void;
(e: 'update:visible', visible: boolean): void;
}>();
// 提交状态
const loading = ref(false);
// 是否显示最大化切换按钮
const maxable = ref(true);
// 表格选中数据
const formRef = ref<FormInstance | null>(null);
// 用户信息
const form = reactive<DesignCategory>({
id: undefined,
title: undefined,
userId: undefined,
sortNumber: undefined,
});
/* 更新visible */
const updateVisible = (value: boolean) => {
emit('update:visible', value);
};
// 表单验证规则
const rules = reactive({
designCategoryName: [
{
required: true,
type: 'string',
message: '请填写设计征集报名分类名称',
trigger: 'blur'
}
]
});
const {resetFields} = useForm(form, rules);
/* 保存编辑 */
const save = () => {
if (!formRef.value) {
return;
}
formRef.value
.validate()
.then(() => {
loading.value = true;
const formData = {
...form
};
const saveOrUpdate = isUpdate.value ? updateDesignCategory : addDesignCategory;
saveOrUpdate(formData)
.then((msg) => {
loading.value = false;
message.success(msg);
updateVisible(false);
emit('done');
})
.catch((e) => {
loading.value = false;
message.error(e.message);
});
})
.catch(() => {
});
};
watch(
() => props.visible,
(visible) => {
if (visible) {
if (props.data) {
assignObject(form, props.data);
isUpdate.value = true;
} else {
isUpdate.value = false;
}
} else {
resetFields();
}
},
{immediate: true}
);
</script>

View File

@@ -0,0 +1,42 @@
<!-- 搜索表单 -->
<template>
<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-space>
</template>
<script lang="ts" setup>
import { PlusOutlined } from '@ant-design/icons-vue';
import type { GradeParam } from '@/api/user/grade/model';
import { watch } from 'vue';
const props = withDefaults(
defineProps<{
// 选中的角色
selection?: [];
}>(),
{}
);
const emit = defineEmits<{
(e: 'search', where?: GradeParam): void;
(e: 'add'): void;
(e: 'remove'): void;
(e: 'batchMove'): void;
}>();
// 新增
const add = () => {
emit('add');
};
watch(
() => props.selection,
() => {}
);
</script>

View File

@@ -0,0 +1,221 @@
<template>
<div class="page">
<div class="ele-body">
<a-card :bordered="false" :body-style="{ padding: '16px' }">
<ele-pro-table
ref="tableRef"
row-key="designCategoryId"
:columns="columns"
:datasource="datasource"
:customRow="customRow"
tool-class="ele-toolbar-form"
class="sys-org-table"
>
<template #toolbar>
<search
@search="reload"
:selection="selection"
@add="openEdit"
@remove="removeBatch"
@batchMove="openMove"
/>
</template>
<template #bodyCell="{ column, record }">
<template v-if="column.key === 'image'">
<a-image :src="record.image" :width="50" />
</template>
<template v-if="column.key === 'status'">
<a-tag v-if="record.status === 0" color="green">显示</a-tag>
<a-tag v-if="record.status === 1" color="red">隐藏</a-tag>
</template>
<template v-if="column.key === 'action'">
<a-space>
<a @click="openEdit(record)">修改</a>
<a-divider type="vertical" />
<a-popconfirm
title="确定要删除此记录吗?"
@confirm="remove(record)"
>
<a class="ele-text-danger">删除</a>
</a-popconfirm>
</a-space>
</template>
</template>
</ele-pro-table>
</a-card>
<!-- 编辑弹窗 -->
<DesignCategoryEdit v-model:visible="showEdit" :data="current" @done="reload" />
</div>
</div>
</template>
<script lang="ts" setup>
import { createVNode, ref } 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
} from 'ele-admin-pro/es/ele-pro-table/types';
import Search from './components/search.vue';
import DesignCategoryEdit from './components/designCategoryEdit.vue';
import { pageDesignCategory, removeDesignCategory, removeBatchDesignCategory } from '@/api/cms/designCategory';
import type { DesignCategory, DesignCategoryParam } from '@/api/cms/designCategory/model';
// 表格实例
const tableRef = ref<InstanceType<typeof EleProTable> | null>(null);
// 表格选中数据
const selection = ref<DesignCategory[]>([]);
// 当前编辑数据
const current = ref<DesignCategory | null>(null);
// 是否显示编辑弹窗
const showEdit = ref(false);
// 是否显示批量移动弹窗
const showMove = ref(false);
// 加载状态
const loading = ref(true);
// 表格数据源
const datasource: DatasourceFunction = ({
page,
limit,
where,
orders,
filters
}) => {
if (filters) {
where.status = filters.status;
}
return pageDesignCategory({
...where,
...orders,
page,
limit
});
};
// 表格列配置
const columns = ref<ColumnItem[]>([
{
title: 'ID',
dataIndex: 'id',
key: 'id',
align: 'center',
width: 90,
},
{
title: '标题',
dataIndex: 'title',
key: 'title',
align: 'center',
},
{
title: '创建时间',
dataIndex: 'createTime',
key: 'createTime',
align: 'center',
sorter: true,
ellipsis: true,
customRender: ({ text }) => toDateString(text, 'yyyy-MM-dd')
},
{
title: '操作',
key: 'action',
width: 180,
fixed: 'right',
align: 'center',
hideInSetting: true
}
]);
/* 搜索 */
const reload = (where?: DesignCategoryParam) => {
selection.value = [];
tableRef?.value?.reload({ where: where });
};
/* 打开编辑弹窗 */
const openEdit = (row?: DesignCategory) => {
current.value = row ?? null;
showEdit.value = true;
};
/* 打开批量移动弹窗 */
const openMove = () => {
showMove.value = true;
};
/* 删除单个 */
const remove = (row: DesignCategory) => {
const hide = message.loading('请求中..', 0);
removeDesignCategory(row.designCategoryId)
.then((msg) => {
hide();
message.success(msg);
reload();
})
.catch((e) => {
hide();
message.error(e.message);
});
};
/* 批量删除 */
const removeBatch = () => {
if (!selection.value.length) {
message.error('请至少选择一条数据');
return;
}
Modal.confirm({
title: '提示',
content: '确定要删除选中的记录吗?',
icon: createVNode(ExclamationCircleOutlined),
maskClosable: true,
onOk: () => {
const hide = message.loading('请求中..', 0);
removeBatchDesignCategory(selection.value.map((d) => d.designCategoryId))
.then((msg) => {
hide();
message.success(msg);
reload();
})
.catch((e) => {
hide();
message.error(e.message);
});
}
});
};
/* 查询 */
const query = () => {
loading.value = true;
};
/* 自定义行属性 */
const customRow = (record: DesignCategory) => {
return {
// 行点击事件
onClick: () => {
// console.log(record);
},
// 行双击事件
onDblclick: () => {
openEdit(record);
}
};
};
query();
</script>
<script lang="ts">
export default {
name: 'DesignCategory'
};
</script>
<style lang="less" scoped></style>

View File

@@ -0,0 +1,310 @@
<!-- 编辑弹窗 -->
<template>
<ele-modal
:width="800"
:visible="visible"
:maskClosable="false"
:maxable="maxable"
:title="isUpdate ? '编辑设计征集' : '添加设计征集'"
:body-style="{ paddingBottom: '28px' }"
@update:visible="updateVisible"
@ok="save"
>
<a-form
ref="formRef"
:model="form"
:rules="rules"
>
<a-form-item label="标题" name="title">
<a-input
allow-clear
placeholder="请输入标题"
v-model:value="form.title"
/>
</a-form-item>
<a-form-item label="分类" name="categoryId">
<a-select v-model:value="form.categoryId">
<a-select-option v-for="(item, index) in cateList" :key="index" :value="item.id">{{ item.title }}</a-select-option>
</a-select>
</a-form-item>
<a-form-item label="内容" required>
<tinymce-editor
ref="editorRef"
class="content"
v-model:value="content"
:init="config"
placeholder="图片直接粘贴自动上传"
@paste="onPaste"
/>
</a-form-item>
<a-form-item
label="封面"
name="image">
<SelectFile
:placeholder="`请选择图片`"
:limit="1"
:data="images"
@done="chooseImage"
@del="onDeleteItem"
/>
</a-form-item>
<a-form-item label="排序(数字越小越靠前)" name="sortNumber">
<a-input-number
:min="0"
:max="9999"
class="ele-fluid"
placeholder="请输入排序号"
v-model:value="form.sortNumber"
/>
</a-form-item>
<a-form-item label="备注" name="comments">
<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 {Form, message} from 'ant-design-vue';
import {assignObject, uuid} from 'ele-admin-pro';
import {addDesignCollect, updateDesignCollect} from '@/api/cms/designCollect';
import {DesignCollect} from '@/api/cms/designCollect/model';
import {useThemeStore} from '@/store/modules/theme';
import {storeToRefs} from 'pinia';
import {ItemType} from 'ele-admin-pro/es/ele-image-upload/types';
import {FormInstance} from 'ant-design-vue/es/form';
import {FileRecord} from '@/api/system/file/model';
import TinymceEditor from "@/components/TinymceEditor/index.vue";
import {uploadFile, uploadOss} from "@/api/system/file";
import {DesignCategory} from "@/api/cms/designCategory/model";
import {listDesignCategory} from "@/api/cms/designCategory";
// 是否是修改
const isUpdate = ref(false);
const useForm = Form.useForm;
// 是否开启响应式布局
const themeStore = useThemeStore();
const {styleResponsive} = storeToRefs(themeStore);
const props = defineProps<{
// 弹窗是否打开
visible: boolean;
// 修改回显的数据
data?: DesignCollect | null;
}>();
const emit = defineEmits<{
(e: 'done'): void;
(e: 'update:visible', visible: boolean): void;
}>();
// 提交状态
const loading = ref(false);
// 是否显示最大化切换按钮
const maxable = ref(true);
// 表格选中数据
const formRef = ref<FormInstance | null>(null);
const images = ref<ItemType[]>([]);
// 用户信息
const form = reactive<DesignCollect>({
id: undefined,
title: undefined,
categoryId: undefined,
content: undefined,
image: undefined,
userId: undefined,
sortNumber: undefined,
comments: undefined,
status: undefined,
deleted: undefined,
tenantId: undefined,
createTime: undefined,
updateTime: undefined,
});
/* 更新visible */
const updateVisible = (value: boolean) => {
emit('update:visible', value);
};
// 表单验证规则
const rules = reactive({
title: [{required: true, message: '请输入标题', trigger: 'blur'}],
image: [{required: true, message: '请上传封面', trigger: 'blur'}],
categoryId: [{required: true, message: '请选择分类', trigger: 'blur'}],
});
const chooseImage = (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 content = ref('');
const editorRef = ref<InstanceType<typeof TinymceEditor> | null>(null);
const config = ref({
height: 500,
images_upload_handler: (blobInfo, success, error) => {
const file = blobInfo.blob();
const formData = new FormData();
formData.append('file', file, file.name);
uploadOss(file).then(res => {
success(res.path)
}).catch((msg) => {
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();
}
});
/* 粘贴图片上传服务器并插入编辑器 */
const onPaste = (e) => {
const items = (e.clipboardData || e.originalEvent.clipboardData).items;
let hasFile = false;
for (let i = 0; i < items.length; i++) {
if (items[i].type.indexOf('image') !== -1) {
let file = items[i].getAsFile();
const item: ItemType = {
file,
uid: (file as any).lastModified,
name: file.name
};
uploadFile(<File>item.file)
.then((result) => {
const addPath = `<p><img class="content-img" src="${result.url}"></p>`;
content.value = content.value + addPath
})
.catch((e) => {
message.error(e.message);
});
hasFile = true;
}
}
if (hasFile) {
e.preventDefault();
}
}
const {resetFields} = useForm(form, rules);
/* 保存编辑 */
const save = () => {
if (!formRef.value) {
return;
}
formRef.value
.validate()
.then(() => {
loading.value = true;
const formData = {
...form
};
if (!content.value) {
return message.error('请输入内容')
}
formData.content = content.value;
const saveOrUpdate = isUpdate.value ? updateDesignCollect : addDesignCollect;
saveOrUpdate(formData)
.then((msg) => {
loading.value = false;
message.success(msg);
updateVisible(false);
emit('done');
})
.catch((e) => {
loading.value = false;
message.error(e.message);
});
})
.catch(() => {
});
};
const cateList = ref<DesignCategory[]>([]);
const getCateList = async () => {
cateList.value = await listDesignCategory()
}
watch(
() => props.visible,
async (visible) => {
if (visible) {
await getCateList()
images.value = [];
content.value = ''
if (props.data) {
assignObject(form, props.data);
if (props.data.image) {
images.value.push({
uid: uuid(),
url: props.data.image,
status: 'done'
})
}
if (props.data.content) {
content.value = props.data.content;
}
isUpdate.value = true;
} else {
isUpdate.value = false;
}
} else {
resetFields();
}
},
{immediate: true}
);
</script>

View File

@@ -0,0 +1,42 @@
<!-- 搜索表单 -->
<template>
<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-space>
</template>
<script lang="ts" setup>
import { PlusOutlined } from '@ant-design/icons-vue';
import type { GradeParam } from '@/api/user/grade/model';
import { watch } from 'vue';
const props = withDefaults(
defineProps<{
// 选中的角色
selection?: [];
}>(),
{}
);
const emit = defineEmits<{
(e: 'search', where?: GradeParam): void;
(e: 'add'): void;
(e: 'remove'): void;
(e: 'batchMove'): void;
}>();
// 新增
const add = () => {
emit('add');
};
watch(
() => props.selection,
() => {}
);
</script>

View File

@@ -0,0 +1,127 @@
<!-- 编辑弹窗 -->
<template>
<ele-modal
:width="'70%'"
:visible="visible"
:maskClosable="false"
:maxable="maxable"
title="设计征集报名列表"
:body-style="{ paddingBottom: '28px' }"
:footer="null"
@update:visible="updateVisible"
>
<ele-pro-table
ref="tableRef"
row-key="designSignUpId"
:columns="columns"
:datasource="datasource"
tool-class="ele-toolbar-form"
class="sys-org-table"
>
<template #bodyCell="{ column, record }">
<template v-if="column.key === 'content'">
<div class="flex flex-wrap justify-start items-start">
<a-image-preview-group>
<a-space>
<a-image class="image" v-for="(item, index) in JSON.parse(record.content)" :key="index" :src="item.url" :width="50" :height="50"/>
</a-space>
</a-image-preview-group>
</div>
</template>
</template>
</ele-pro-table>
</ele-modal>
</template>
<script lang="ts" setup>
import {ref, watch} from 'vue';
import {DesignCollect} from '@/api/cms/designCollect/model';
import {pageDesignSignUp} from "@/api/cms/designSignUp";
import {EleProTable, toDateString} from "ele-admin-pro";
import type {ColumnItem, DatasourceFunction} from "ele-admin-pro/es/ele-pro-table/types";
const props = defineProps<{
// 弹窗是否打开
visible: boolean;
// 修改回显的数据
data?: DesignCollect | null;
}>();
const emit = defineEmits<{
(e: 'done'): void;
(e: 'update:visible', visible: boolean): void;
}>();
// 提交状态
const loading = ref(false);
// 是否显示最大化切换按钮
const maxable = ref(true);
const columns = ref<ColumnItem[]>([
{
title: '姓名',
dataIndex: 'name',
key: 'name',
align: 'center',
},
{
title: '手机号',
dataIndex: 'phone',
key: 'phone',
align: 'center',
},
{
title: '内容',
key: 'content',
align: 'center',
},
{
title: '提交时间',
dataIndex: 'createTime',
key: 'createTime',
align: 'center',
sorter: true,
ellipsis: true,
customRender: ({text}) => toDateString(text, 'yyyy-MM-dd HH:mm:ss')
},
]);
/* 更新visible */
const updateVisible = (value: boolean) => {
emit('update:visible', value);
};
const datasource: DatasourceFunction = ({
page,
limit,
where,
orders,
}) => {
where.designId = props.data?.id;
return pageDesignSignUp({
...where,
...orders,
page,
limit
});
};
watch(
() => props.visible,
(visible) => {
if (visible) {
} else {
}
},
{immediate: true}
);
</script>
<style>
.image{
width: 100%;
height: 100%;
object-fit: cover;
}
</style>

View File

@@ -0,0 +1,243 @@
<template>
<div class="page">
<div class="ele-body">
<a-card :bordered="false" :body-style="{ padding: '16px' }">
<ele-pro-table
ref="tableRef"
row-key="designCollectId"
:columns="columns"
:datasource="datasource"
:customRow="customRow"
tool-class="ele-toolbar-form"
class="sys-org-table"
>
<template #toolbar>
<search
@search="reload"
:selection="selection"
@add="openEdit"
@remove="removeBatch"
@batchMove="openMove"
/>
</template>
<template #bodyCell="{ column, record }">
<template v-if="column.key === 'image'">
<a-image :src="record.image" :width="50"/>
</template>
<template v-if="column.key === 'status'">
<a-tag v-if="record.status === 0" color="green">显示</a-tag>
<a-tag v-if="record.status === 1" color="red">隐藏</a-tag>
</template>
<template v-if="column.key === 'action'">
<a-space>
<a @click="openList(record)">报名详情</a>
<a-divider type="vertical"/>
<a @click="openEdit(record)">修改</a>
<a-divider type="vertical"/>
<a-popconfirm
title="确定要删除此记录吗?"
@confirm="remove(record)"
>
<a class="ele-text-danger">删除</a>
</a-popconfirm>
</a-space>
</template>
</template>
</ele-pro-table>
</a-card>
<!-- 编辑弹窗 -->
<DesignCollectEdit v-model:visible="showEdit" :data="current" @done="reload"/>
<SignUpList v-model:visible="showList" :data="current" @done="reload"/>
</div>
</div>
</template>
<script lang="ts" setup>
import {createVNode, ref} 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
} from 'ele-admin-pro/es/ele-pro-table/types';
import Search from './components/search.vue';
import DesignCollectEdit from './components/designCollectEdit.vue';
import {pageDesignCollect, removeDesignCollect, removeBatchDesignCollect} from '@/api/cms/designCollect';
import type {DesignCollect, DesignCollectParam} from '@/api/cms/designCollect/model';
import SignUpList from "@/views/cms/designCollect/components/signUpList.vue";
// 表格实例
const tableRef = ref<InstanceType<typeof EleProTable> | null>(null);
// 表格选中数据
const selection = ref<DesignCollect[]>([]);
// 当前编辑数据
const current = ref<DesignCollect | null>(null);
// 是否显示编辑弹窗
const showEdit = ref(false);
// 是否显示批量移动弹窗
const showMove = ref(false);
// 加载状态
const loading = ref(true);
// 表格数据源
const datasource: DatasourceFunction = ({
page,
limit,
where,
orders,
filters
}) => {
if (filters) {
where.status = filters.status;
}
return pageDesignCollect({
...where,
...orders,
page,
limit
});
};
// 表格列配置
const columns = ref<ColumnItem[]>([
{
title: 'ID',
dataIndex: 'id',
key: 'id',
align: 'center',
width: 90,
},
{
title: '标题',
dataIndex: 'title',
key: 'title',
align: 'center',
},
{
title: '分类',
dataIndex: ['category', 'title'],
key: 'title',
align: 'center',
},
{
title: '排序(数字越小越靠前)',
dataIndex: 'sortNumber',
key: 'sortNumber',
align: 'center',
},
{
title: '创建时间',
dataIndex: 'createTime',
key: 'createTime',
align: 'center',
sorter: true,
ellipsis: true,
customRender: ({text}) => toDateString(text, 'yyyy-MM-dd')
},
{
title: '操作',
key: 'action',
width: 180,
fixed: 'right',
align: 'center',
hideInSetting: true
}
]);
/* 搜索 */
const reload = (where?: DesignCollectParam) => {
selection.value = [];
tableRef?.value?.reload({where: where});
};
/* 打开编辑弹窗 */
const openEdit = (row?: DesignCollect) => {
current.value = row ?? null;
showEdit.value = true;
};
const showList = ref(false)
const openList = (row?: DesignCollect) => {
current.value = row ?? null;
showList.value = true;
};
/* 打开批量移动弹窗 */
const openMove = () => {
showMove.value = true;
};
/* 删除单个 */
const remove = (row: DesignCollect) => {
const hide = message.loading('请求中..', 0);
removeDesignCollect(row.designCollectId)
.then((msg) => {
hide();
message.success(msg);
reload();
})
.catch((e) => {
hide();
message.error(e.message);
});
};
/* 批量删除 */
const removeBatch = () => {
if (!selection.value.length) {
message.error('请至少选择一条数据');
return;
}
Modal.confirm({
title: '提示',
content: '确定要删除选中的记录吗?',
icon: createVNode(ExclamationCircleOutlined),
maskClosable: true,
onOk: () => {
const hide = message.loading('请求中..', 0);
removeBatchDesignCollect(selection.value.map((d) => d.designCollectId))
.then((msg) => {
hide();
message.success(msg);
reload();
})
.catch((e) => {
hide();
message.error(e.message);
});
}
});
};
/* 查询 */
const query = () => {
loading.value = true;
};
/* 自定义行属性 */
const customRow = (record: DesignCollect) => {
return {
// 行点击事件
onClick: () => {
// console.log(record);
},
// 行双击事件
onDblclick: () => {
openEdit(record);
}
};
};
query();
</script>
<script lang="ts">
export default {
name: 'DesignCollect'
};
</script>
<style lang="less" scoped></style>

View File

@@ -0,0 +1,244 @@
<!-- 编辑弹窗 -->
<template>
<ele-modal
:width="800"
:visible="visible"
:maskClosable="false"
:maxable="maxable"
:title="isUpdate ? '编辑设计征集报名' : '添加设计征集报名'"
:body-style="{ paddingBottom: '28px' }"
@update:visible="updateVisible"
@ok="save"
>
<a-form
ref="formRef"
:model="form"
:rules="rules"
:label-col="styleResponsive ? { md: 4, sm: 5, xs: 24 } : { flex: '90px' }"
:wrapper-col="
styleResponsive ? { md: 19, sm: 19, xs: 24 } : { flex: '1' }
"
>
<a-form-item label="" name="designId">
<a-input
allow-clear
placeholder="请输入"
v-model:value="form.designId"
/>
</a-form-item>
<a-form-item label="" name="name">
<a-input
allow-clear
placeholder="请输入"
v-model:value="form.name"
/>
</a-form-item>
<a-form-item label="" name="phone">
<a-input
allow-clear
placeholder="请输入"
v-model:value="form.phone"
/>
</a-form-item>
<a-form-item label="" name="content">
<a-input
allow-clear
placeholder="请输入"
v-model:value="form.content"
/>
</a-form-item>
<a-form-item label="用户ID" name="userId">
<a-input
allow-clear
placeholder="请输入用户ID"
v-model:value="form.userId"
/>
</a-form-item>
<a-form-item label="排序(数字越小越靠前)" name="sortNumber">
<a-input-number
:min="0"
:max="9999"
class="ele-fluid"
placeholder="请输入排序号"
v-model:value="form.sortNumber"
/>
</a-form-item>
<a-form-item label="备注" name="comments">
<a-textarea
:rows="4"
:maxlength="200"
placeholder="请输入描述"
v-model:value="form.comments"
/>
</a-form-item>
<a-form-item label="状态, 0已发布, 1待审核 2已驳回 3违规内容" name="status">
<a-radio-group v-model:value="form.status">
<a-radio :value="0">显示</a-radio>
<a-radio :value="1">隐藏</a-radio>
</a-radio-group>
</a-form-item>
<a-form-item label="是否删除, 0否, 1是" name="deleted">
<a-input
allow-clear
placeholder="请输入是否删除, 0否, 1是"
v-model:value="form.deleted"
/>
</a-form-item>
<a-form-item label="修改时间" name="updateTime">
<a-input
allow-clear
placeholder="请输入修改时间"
v-model:value="form.updateTime"
/>
</a-form-item>
</a-form>
</ele-modal>
</template>
<script lang="ts" setup>
import { ref, reactive, watch } from 'vue';
import { Form, message } from 'ant-design-vue';
import { assignObject, uuid } from 'ele-admin-pro';
import { addDesignSignUp, updateDesignSignUp } from '@/api/cms/designSignUp';
import { DesignSignUp } from '@/api/cms/designSignUp/model';
import { useThemeStore } from '@/store/modules/theme';
import { storeToRefs } from 'pinia';
import { ItemType } from 'ele-admin-pro/es/ele-image-upload/types';
import { FormInstance } from 'ant-design-vue/es/form';
import { FileRecord } from '@/api/system/file/model';
// 是否是修改
const isUpdate = ref(false);
const useForm = Form.useForm;
// 是否开启响应式布局
const themeStore = useThemeStore();
const { styleResponsive } = storeToRefs(themeStore);
const props = defineProps<{
// 弹窗是否打开
visible: boolean;
// 修改回显的数据
data?: DesignSignUp | null;
}>();
const emit = defineEmits<{
(e: 'done'): void;
(e: 'update:visible', visible: boolean): void;
}>();
// 提交状态
const loading = ref(false);
// 是否显示最大化切换按钮
const maxable = ref(true);
// 表格选中数据
const formRef = ref<FormInstance | null>(null);
const images = ref<ItemType[]>([]);
// 用户信息
const form = reactive<DesignSignUp>({
id: undefined,
designId: undefined,
name: undefined,
phone: undefined,
content: undefined,
userId: undefined,
sortNumber: undefined,
comments: undefined,
status: undefined,
deleted: undefined,
tenantId: undefined,
createTime: undefined,
updateTime: undefined,
designSignUpId: undefined,
designSignUpName: '',
status: 0,
comments: '',
sortNumber: 100
});
/* 更新visible */
const updateVisible = (value: boolean) => {
emit('update:visible', value);
};
// 表单验证规则
const rules = reactive({
designSignUpName: [
{
required: true,
type: 'string',
message: '请填写设计征集报名名称',
trigger: 'blur'
}
]
});
const chooseImage = (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 { resetFields } = useForm(form, rules);
/* 保存编辑 */
const save = () => {
if (!formRef.value) {
return;
}
formRef.value
.validate()
.then(() => {
loading.value = true;
const formData = {
...form
};
const saveOrUpdate = isUpdate.value ? updateDesignSignUp : addDesignSignUp;
saveOrUpdate(formData)
.then((msg) => {
loading.value = false;
message.success(msg);
updateVisible(false);
emit('done');
})
.catch((e) => {
loading.value = false;
message.error(e.message);
});
})
.catch(() => {});
};
watch(
() => props.visible,
(visible) => {
if (visible) {
images.value = [];
if (props.data) {
assignObject(form, props.data);
if(props.data.image){
images.value.push({
uid: uuid(),
url: props.data.image,
status: 'done'
})
}
isUpdate.value = true;
} else {
isUpdate.value = false;
}
} else {
resetFields();
}
},
{ immediate: true }
);
</script>

View File

@@ -0,0 +1,42 @@
<!-- 搜索表单 -->
<template>
<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-space>
</template>
<script lang="ts" setup>
import { PlusOutlined } from '@ant-design/icons-vue';
import type { GradeParam } from '@/api/user/grade/model';
import { watch } from 'vue';
const props = withDefaults(
defineProps<{
// 选中的角色
selection?: [];
}>(),
{}
);
const emit = defineEmits<{
(e: 'search', where?: GradeParam): void;
(e: 'add'): void;
(e: 'remove'): void;
(e: 'batchMove'): void;
}>();
// 新增
const add = () => {
emit('add');
};
watch(
() => props.selection,
() => {}
);
</script>

View File

@@ -0,0 +1,275 @@
<template>
<div class="page">
<div class="ele-body">
<a-card :bordered="false" :body-style="{ padding: '16px' }">
<ele-pro-table
ref="tableRef"
row-key="designSignUpId"
:columns="columns"
:datasource="datasource"
:customRow="customRow"
tool-class="ele-toolbar-form"
class="sys-org-table"
>
<template #toolbar>
<search
@search="reload"
:selection="selection"
@add="openEdit"
@remove="removeBatch"
@batchMove="openMove"
/>
</template>
<template #bodyCell="{ column, record }">
<template v-if="column.key === 'image'">
<a-image :src="record.image" :width="50" />
</template>
<template v-if="column.key === 'status'">
<a-tag v-if="record.status === 0" color="green">显示</a-tag>
<a-tag v-if="record.status === 1" color="red">隐藏</a-tag>
</template>
<template v-if="column.key === 'action'">
<a-space>
<a @click="openEdit(record)">修改</a>
<a-divider type="vertical" />
<a-popconfirm
title="确定要删除此记录吗?"
@confirm="remove(record)"
>
<a class="ele-text-danger">删除</a>
</a-popconfirm>
</a-space>
</template>
</template>
</ele-pro-table>
</a-card>
<!-- 编辑弹窗 -->
<DesignSignUpEdit v-model:visible="showEdit" :data="current" @done="reload" />
</div>
</div>
</template>
<script lang="ts" setup>
import { createVNode, ref } 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
} from 'ele-admin-pro/es/ele-pro-table/types';
import Search from './components/search.vue';
import DesignSignUpEdit from './components/designSignUpEdit.vue';
import { pageDesignSignUp, removeDesignSignUp, removeBatchDesignSignUp } from '@/api/cms/designSignUp';
import type { DesignSignUp, DesignSignUpParam } from '@/api/cms/designSignUp/model';
// 表格实例
const tableRef = ref<InstanceType<typeof EleProTable> | null>(null);
// 表格选中数据
const selection = ref<DesignSignUp[]>([]);
// 当前编辑数据
const current = ref<DesignSignUp | null>(null);
// 是否显示编辑弹窗
const showEdit = ref(false);
// 是否显示批量移动弹窗
const showMove = ref(false);
// 加载状态
const loading = ref(true);
// 表格数据源
const datasource: DatasourceFunction = ({
page,
limit,
where,
orders,
filters
}) => {
if (filters) {
where.status = filters.status;
}
return pageDesignSignUp({
...where,
...orders,
page,
limit
});
};
// 表格列配置
const columns = ref<ColumnItem[]>([
{
title: '',
dataIndex: 'id',
key: 'id',
align: 'center',
width: 90,
},
{
title: '',
dataIndex: 'designId',
key: 'designId',
align: 'center',
},
{
title: '',
dataIndex: 'name',
key: 'name',
align: 'center',
},
{
title: '',
dataIndex: 'phone',
key: 'phone',
align: 'center',
},
{
title: '',
dataIndex: 'content',
key: 'content',
align: 'center',
},
{
title: '用户ID',
dataIndex: 'userId',
key: 'userId',
align: 'center',
},
{
title: '排序(数字越小越靠前)',
dataIndex: 'sortNumber',
key: 'sortNumber',
align: 'center',
},
{
title: '备注',
dataIndex: 'comments',
key: 'comments',
align: 'center',
},
{
title: '状态, 0已发布, 1待审核 2已驳回 3违规内容',
dataIndex: 'status',
key: 'status',
align: 'center',
},
{
title: '是否删除, 0否, 1是',
dataIndex: 'deleted',
key: 'deleted',
align: 'center',
},
{
title: '创建时间',
dataIndex: 'createTime',
key: 'createTime',
align: 'center',
sorter: true,
ellipsis: true,
customRender: ({ text }) => toDateString(text, 'yyyy-MM-dd')
},
{
title: '修改时间',
dataIndex: 'updateTime',
key: 'updateTime',
align: 'center',
},
{
title: '操作',
key: 'action',
width: 180,
fixed: 'right',
align: 'center',
hideInSetting: true
}
]);
/* 搜索 */
const reload = (where?: DesignSignUpParam) => {
selection.value = [];
tableRef?.value?.reload({ where: where });
};
/* 打开编辑弹窗 */
const openEdit = (row?: DesignSignUp) => {
current.value = row ?? null;
showEdit.value = true;
};
/* 打开批量移动弹窗 */
const openMove = () => {
showMove.value = true;
};
/* 删除单个 */
const remove = (row: DesignSignUp) => {
const hide = message.loading('请求中..', 0);
removeDesignSignUp(row.designSignUpId)
.then((msg) => {
hide();
message.success(msg);
reload();
})
.catch((e) => {
hide();
message.error(e.message);
});
};
/* 批量删除 */
const removeBatch = () => {
if (!selection.value.length) {
message.error('请至少选择一条数据');
return;
}
Modal.confirm({
title: '提示',
content: '确定要删除选中的记录吗?',
icon: createVNode(ExclamationCircleOutlined),
maskClosable: true,
onOk: () => {
const hide = message.loading('请求中..', 0);
removeBatchDesignSignUp(selection.value.map((d) => d.designSignUpId))
.then((msg) => {
hide();
message.success(msg);
reload();
})
.catch((e) => {
hide();
message.error(e.message);
});
}
});
};
/* 查询 */
const query = () => {
loading.value = true;
};
/* 自定义行属性 */
const customRow = (record: DesignSignUp) => {
return {
// 行点击事件
onClick: () => {
// console.log(record);
},
// 行双击事件
onDblclick: () => {
openEdit(record);
}
};
};
query();
</script>
<script lang="ts">
export default {
name: 'DesignSignUp'
};
</script>
<style lang="less" scoped></style>

View File

@@ -0,0 +1,179 @@
<!-- 分类编辑弹窗 -->
<template>
<ele-modal
:width="460"
: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: 5, sm: 5, xs: 24 } : { flex: '90px' }"
:wrapper-col="
styleResponsive ? { md: 19, sm: 19, xs: 24 } : { flex: '1' }
"
>
<a-form-item label="分类标识" name="dictCode">
<a-input
:maxlength="20"
disabled
placeholder="请输入分类标识"
v-model:value="form.dictCode"
/>
</a-form-item>
<a-form-item label="分类名称" name="dictDataName">
<a-input
allow-clear
:maxlength="20"
placeholder="请输入分类名称"
v-model:value="form.dictDataName"
/>
</a-form-item>
<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-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 { addDictData, updateDictData } from '@/api/system/dict-data';
import { DictData } from '@/api/system/dict-data/model';
import { removeSiteInfoCache } from '@/api/cms/website';
// 是否开启响应式布局
const themeStore = useThemeStore();
const { styleResponsive } = storeToRefs(themeStore);
const emit = defineEmits<{
(e: 'done'): void;
(e: 'update:visible', visible: boolean): void;
}>();
const props = defineProps<{
// 弹窗是否打开
visible: boolean;
// 修改回显的数据
data?: DictData | null;
// 字典ID
dictId?: number | 0;
}>();
//
const formRef = ref<FormInstance | null>(null);
// 是否是修改
const isUpdate = ref(false);
// 提交状态
const loading = ref(false);
// 表单数据
const { form, resetFields, assignFields } = useFormData<DictData>({
dictId: undefined,
dictName: '',
dictDataId: undefined,
dictDataName: '',
dictCode: 'linkType',
dictDataCode: '',
sortNumber: 100,
comments: ''
});
// 表单验证规则
const rules = reactive<Record<string, Rule[]>>({
dictDataCode: [
{
required: true,
message: '请输入分类名称',
type: 'string',
trigger: 'blur'
}
],
dictCode: [
{
required: true,
message: '请输入分类标识',
type: 'string',
trigger: 'blur'
}
]
});
/* 保存编辑 */
const save = () => {
if (!formRef.value) {
return;
}
formRef.value
.validate()
.then(() => {
loading.value = true;
const saveOrUpdate = isUpdate.value ? updateDictData : addDictData;
form.dictDataCode = form.dictDataName;
form.dictId = props.dictId;
form.dictName = '链接分类';
saveOrUpdate(form)
.then((msg) => {
loading.value = false;
message.success(msg);
// 清除缓存
removeSiteInfoCache(form.dictCode + ':' + form.tenantId);
updateVisible(false);
emit('done');
})
.catch((e) => {
loading.value = false;
message.error(e.message);
});
})
.catch(() => {});
};
/* 更新visible */
const updateVisible = (value: boolean) => {
emit('update:visible', value);
};
watch(
() => props.visible,
(visible) => {
if (visible) {
if (props.data) {
assignFields(props.data);
isUpdate.value = true;
} else {
isUpdate.value = false;
}
} else {
resetFields();
formRef.value?.clearValidate();
}
}
);
</script>

View File

@@ -0,0 +1,211 @@
<template>
<div class="ele-body">
<a-card :bordered="false">
<!-- 表格 -->
<ele-pro-table
ref="tableRef"
row-key="dictDataId"
:columns="columns"
:datasource="datasource"
:customRow="customRow"
:scroll="{ x: 800 }"
cache-key="proSystemRoleTable"
>
<template #toolbar>
<a-space>
<a-button type="primary" class="ele-btn-icon" @click="openEdit()">
<template #icon>
<plus-outlined />
</template>
<span>新建</span>
</a-button>
</a-space>
</template>
<template #bodyCell="{ column, record }">
<template v-if="column.key === 'action'">
<a-space>
<a @click="openEdit(record)">修改</a>
<a-divider type="vertical" />
<a-popconfirm
placement="topRight"
title="确定要删除此分类吗?"
@confirm="remove(record)"
>
<a class="ele-text-danger">删除</a>
</a-popconfirm>
</a-space>
</template>
</template>
</ele-pro-table>
</a-card>
<!-- 编辑弹窗 -->
<dict-edit
v-model:visible="showEdit"
:dictId="dictId"
:data="current"
@done="reload"
/>
</div>
</template>
<script lang="ts" setup>
import { createVNode, ref } from 'vue';
import { message, Modal } from 'ant-design-vue/es';
import {
PlusOutlined,
DeleteOutlined,
ExclamationCircleOutlined
} from '@ant-design/icons-vue';
import type { EleProTable } from 'ele-admin-pro/es';
import type {
DatasourceFunction,
ColumnItem
} from 'ele-admin-pro/es/ele-pro-table/types';
import { messageLoading } from 'ele-admin-pro/es';
import DictEdit from './components/dict-edit.vue';
import {
pageDictData,
removeDictData,
removeDictDataBatch
} from '@/api/system/dict-data';
import { DictParam } from '@/api/system/dict/model';
import { DictData } from '@/api/system/dict-data/model';
import { addDict, listDictionaries } from '@/api/system/dict';
import { Dictionary } from '@/api/system/dictionary/model';
// 表格实例
const tableRef = ref<InstanceType<typeof EleProTable> | null>(null);
const dictId = ref(0);
// 表格列配置
const columns = ref<ColumnItem[]>([
{
title: 'ID',
dataIndex: 'dictDataId',
width: 80
},
{
title: '分类名称',
dataIndex: 'dictDataName',
showSorterTooltip: false
},
{
title: '备注',
dataIndex: 'comments',
sorter: true,
showSorterTooltip: false
},
{
title: '排序号',
width: 180,
align: 'center',
dataIndex: 'sortNumber'
},
{
title: '操作',
key: 'action',
width: 180,
align: 'center'
}
]);
// 表格选中数据
const selection = ref<DictData[]>([]);
// 当前编辑数据
const current = ref<Dictionary | null>(null);
// 是否显示编辑弹窗
const showEdit = ref(false);
// 表格数据源
const datasource: DatasourceFunction = ({ page, limit, where, orders }) => {
where.dictCode = 'linkType';
return pageDictData({ ...where, ...orders, page, limit });
};
/* 搜索 */
const reload = (where?: DictParam) => {
selection.value = [];
tableRef?.value?.reload({ page: 1, where });
};
/* 打开编辑弹窗 */
const openEdit = (row?: DictData) => {
current.value = row ?? null;
showEdit.value = true;
};
/* 删除单个 */
const remove = (row: DictData) => {
const hide = messageLoading('请求中..', 0);
removeDictData(row.dictDataId)
.then((msg) => {
hide();
message.success(msg);
reload();
})
.catch((e) => {
hide();
message.error(e.message);
});
};
/* 批量删除 */
const removeBatch = () => {
if (!selection.value.length) {
message.error('请至少选择一条数据');
return;
}
Modal.confirm({
title: '提示',
content: '确定要删除选中的分类吗?',
icon: createVNode(ExclamationCircleOutlined),
maskClosable: true,
onOk: () => {
const hide = messageLoading('请求中..', 0);
removeDictDataBatch(selection.value.map((d) => d.dictDataId))
.then((msg) => {
hide();
message.success(msg);
reload();
})
.catch((e) => {
hide();
message.error(e.message);
});
}
});
};
// 初始化字典
const loadDict = () => {
listDictionaries({ dictCode: 'linkType' }).then(async (data) => {
if (data?.length == 0) {
await addDict({ dictCode: 'linkType', dictName: '链接分类' });
}
await listDictionaries({ dictCode: 'linkType' }).then((list) => {
list?.map((d) => {
dictId.value = Number(d.dictId);
});
});
});
};
loadDict();
/* 自定义行属性 */
const customRow = (record: DictData) => {
return {
onDblclick: () => {
openEdit(record);
}
};
};
</script>
<script lang="ts">
export default {
name: 'TaskDictData'
};
</script>

View File

@@ -15,13 +15,14 @@
<template #toolbar>
<a-space>
<a-upload
multiple
:show-upload-list="false"
:accept="'image/*,application/*'"
:customRequest="onUpload"
>
<a-button type="primary" class="ele-btn-icon">
<template #icon>
<UploadOutlined />
<UploadOutlined/>
</template>
<span>上传图片</span>
</a-button>
@@ -34,7 +35,7 @@
@click="removeBatch"
>
<template #icon>
<delete-outlined />
<delete-outlined/>
</template>
<span>批量删除</span>
</a-button>
@@ -83,6 +84,7 @@
</template>
<!-- 含http -->
<template v-else-if="record.path.indexOf('http') == 0">
<div class="bg-gray-300">
<a-image
:src="`${record.thumbnail}`"
:preview="{
@@ -90,6 +92,7 @@
}"
:width="80"
/>
</div>
</template>
<!-- path -->
<template v-else>
@@ -115,7 +118,7 @@
<template v-if="column.key === 'action'">
<a-space>
<a @click="openEdit(record)">编辑</a>
<a-divider type="vertical" />
<a-divider type="vertical"/>
<a-popconfirm
placement="topRight"
title="确定要删除此文件吗?"
@@ -129,53 +132,53 @@
</ele-pro-table>
</a-card>
<!-- 编辑弹窗 -->
<PhotoEdit v-model:visible="showEdit" :data="current" @done="reload" />
<PhotoEdit v-model:visible="showEdit" :data="current" @done="reload"/>
</div>
</template>
<script lang="ts" setup>
import { createVNode, ref } from 'vue';
import { message, Modal } from 'ant-design-vue/es';
import {
import {createVNode, ref} from 'vue';
import {message, Modal} from 'ant-design-vue/es';
import {
UploadOutlined,
DeleteOutlined,
CopyOutlined,
ExclamationCircleOutlined
} from '@ant-design/icons-vue';
import type { EleProTable } from 'ele-admin-pro/es';
import type {
} from '@ant-design/icons-vue';
import type {EleProTable} from 'ele-admin-pro/es';
import type {
DatasourceFunction,
ColumnItem
} from 'ele-admin-pro/es/ele-pro-table/types';
import { messageLoading, toDateString } from 'ele-admin-pro/es';
import PhotoEdit from './components/photo-edit.vue';
import {
} from 'ele-admin-pro/es/ele-pro-table/types';
import {messageLoading, toDateString} from 'ele-admin-pro/es';
import PhotoEdit from './components/photo-edit.vue';
import {
pageFiles,
removeFile,
removeFiles,
uploadOss
} from '@/api/system/file/index';
import type {
} from '@/api/system/file/index';
import type {
FileRecord,
FileRecordParam
} from '@/api/system/file/model/index';
import { copyText, isImage } from '@/utils/common';
import DictSelect from '@/components/DictSelect/index.vue';
import { getMerchantId } from '@/utils/merchant';
} from '@/api/system/file/model/index';
import {copyText, isImage} from '@/utils/common';
import DictSelect from '@/components/DictSelect/index.vue';
import {getMerchantId} from '@/utils/merchant';
// 表格实例
const tableRef = ref<InstanceType<typeof EleProTable> | null>(null);
// 表格选中数据
const selection = ref<FileRecord[]>([]);
// 当前编辑数据
const current = ref<FileRecord | null>(null);
// 是否显示编辑弹窗
const showEdit = ref(false);
const type = ref('name');
const groupId = ref<number>();
const searchText = ref('');
// 表格列配置
const columns = ref<ColumnItem[]>([
// 表格实例
const tableRef = ref<InstanceType<typeof EleProTable> | null>(null);
// 表格选中数据
const selection = ref<FileRecord[]>([]);
// 当前编辑数据
const current = ref<FileRecord | null>(null);
// 是否显示编辑弹窗
const showEdit = ref(false);
const type = ref('name');
const groupId = ref<number>();
const searchText = ref('');
// 表格列配置
const columns = ref<ColumnItem[]>([
// {
// key: 'index',
// width: 48,
@@ -213,7 +216,7 @@
sorter: true,
showSorterTooltip: false,
ellipsis: true,
customRender: ({ text }) => {
customRender: ({text}) => {
if (text < 1024) {
return text + 'B';
} else if (text < 1024 * 1024) {
@@ -240,7 +243,7 @@
width: 180,
showSorterTooltip: false,
ellipsis: true,
customRender: ({ text }) => toDateString(text)
customRender: ({text}) => toDateString(text)
},
{
title: '操作',
@@ -248,10 +251,10 @@
width: 200,
align: 'center'
}
]);
]);
// 表格数据源
const datasource: DatasourceFunction = ({ page, limit, where, orders }) => {
// 表格数据源
const datasource: DatasourceFunction = ({page, limit, where, orders}) => {
if (where.reset) {
where = {};
}
@@ -265,23 +268,23 @@
where.groupId = groupId.value;
}
where.merchantId = getMerchantId();
return pageFiles({ ...where, ...orders, page, limit });
};
return pageFiles({...where, ...orders, page, limit});
};
/* 搜索 */
const reload = (where?: FileRecordParam) => {
/* 搜索 */
const reload = (where?: FileRecordParam) => {
selection.value = [];
tableRef?.value?.reload({ page: 1, where });
};
tableRef?.value?.reload({page: 1, where});
};
/* 打开编辑弹窗 */
const openEdit = (row?: FileRecord) => {
/* 打开编辑弹窗 */
const openEdit = (row?: FileRecord) => {
current.value = row ?? null;
showEdit.value = true;
};
};
/* 删除单个 */
const remove = (row: FileRecord) => {
/* 删除单个 */
const remove = (row: FileRecord) => {
const hide = messageLoading('请求中..', 0);
removeFile(row.id)
.then((msg) => {
@@ -293,10 +296,10 @@
hide();
message.error(e.message);
});
};
};
/* 批量删除 */
const removeBatch = () => {
/* 批量删除 */
const removeBatch = () => {
if (!selection.value.length) {
message.error('请至少选择一条数据');
return;
@@ -320,21 +323,21 @@
});
}
});
};
};
/* 搜索 */
const chooseGroupId = (groupId: number) => {
reload({ groupId });
};
/* 搜索 */
const chooseGroupId = (groupId: number) => {
reload({groupId});
};
const reset = () => {
const reset = () => {
searchText.value = '';
reload({ groupId: 0 });
};
reload({groupId: 0});
};
// 上传文件
const onUpload = (item) => {
const { file } = item;
// 上传文件
const onUpload = (item) => {
const {file} = item;
// if (!file.type.startsWith('image')) {
// message.error('只能选择图片');
// return;
@@ -358,21 +361,21 @@
message.error(e.message);
hide();
});
};
};
/* 自定义行属性 */
const customRow = (record: FileRecord) => {
/* 自定义行属性 */
const customRow = (record: FileRecord) => {
return {
// 行双击事件
onDblclick: () => {
openEdit(record);
}
};
};
};
</script>
<script lang="ts">
export default {
export default {
name: 'VideoIndex'
};
};
</script>

File diff suppressed because it is too large Load Diff

View File

@@ -1,7 +1,7 @@
<!-- 编辑弹窗 -->
<template>
<ele-modal
:width="900"
:width="'80%'"
:visible="visible"
:maskClosable="false"
:maxable="maxable"
@@ -14,38 +14,38 @@
ref="formRef"
:model="form"
:rules="rules"
:label-col="styleResponsive ? { md: 3, sm: 5, xs: 24 } : { flex: '90px' }"
:label-col="styleResponsive ? { md: 4, sm: 5, xs: 24 } : { flex: '90px' }"
:wrapper-col="
styleResponsive ? { md: 24, sm: 24, xs: 24 } : { flex: '1' }
"
>
<a-tabs type="card" v-model:active-key="active" @change="onChange">
<a-tab-pane tab="基本信息" key="base">
<a-form-item label="商品类型" name="type">
<a-space>
<a-button
:type="form.type == 1 ? 'primary' : ''"
@click="onType(1)"
:ghost="form.type == 1"
>实物商品
</a-button
>
<a-button
:type="form.type == 2 ? 'primary' : ''"
@click="onType(2)"
:ghost="form.type == 2"
>虚拟商品
</a-button
>
</a-space>
<div class="ele-text-placeholder">
{{
form.type == 1
? `支持快递邮寄、同城配送或到店自提方式发货`
: '电子券码等,线下到店核销,无需备货'
}}
</div>
</a-form-item>
<!-- <a-form-item label="商品类型" name="type">-->
<!-- <a-space>-->
<!-- <a-button-->
<!-- :type="form.type == 1 ? 'primary' : ''"-->
<!-- @click="onType(1)"-->
<!-- :ghost="form.type == 1"-->
<!-- >实物商品-->
<!-- </a-button-->
<!-- >-->
<!-- <a-button-->
<!-- :type="form.type == 2 ? 'primary' : ''"-->
<!-- @click="onType(2)"-->
<!-- :ghost="form.type == 2"-->
<!-- >虚拟商品-->
<!-- </a-button-->
<!-- >-->
<!-- </a-space>-->
<!-- <div class="ele-text-placeholder">-->
<!-- {{-->
<!-- form.type == 1-->
<!-- ? `支持快递邮寄、同城配送或到店自提方式发货`-->
<!-- : '电子券码等,线下到店核销,无需备货'-->
<!-- }}-->
<!-- </div>-->
<!-- </a-form-item>-->
<a-form-item
v-if="!merchantId"
label="选择店铺"
@@ -59,6 +59,15 @@
@done="chooseMerchantId"
/>
</a-form-item>
<a-form-item label="供应商" name="supplierMerchantId" v-if="!merchantId">
<SelectMerchant
:placeholder="`选择供应商`"
class="input-item"
style="width: 558px"
v-model:value="form.supplierName"
@done="chooseSupplier"
/>
</a-form-item>
<a-form-item label="商品名称" name="goodsName">
<a-input
allow-clear
@@ -76,7 +85,7 @@
@done="chooseGoodsCategory"
/>
</a-form-item>
<a-form-item label="品分类" name="categoryId" v-else>
<a-form-item label="品分类" name="categoryId" v-else>
<SelectGoodsCategory
:merchantId="merchantId"
placeholder="请选择商品分类"
@@ -120,10 +129,12 @@
v-model:value="form.price"
/>
<a-checkbox v-model:checked="form.priceGift">有赠品</a-checkbox>
<a-input-number v-if="form.priceGift" v-model:value="form.priceGiftNum" style="width: 200px"
placeholder="请输入赠品数量"/>
</a-space>
<div class="ele-text-placeholder">商品的实际购买金额最低0.01</div>
</a-form-item>
<a-form-item label="经销商" name="buyingPrice">
<a-form-item label="经销商" name="dealerPrice" v-if="!merchantId">
<a-space>
<a-input-number
:placeholder="`经销商价格`"
@@ -132,10 +143,12 @@
v-model:value="form.dealerPrice"
/>
<a-checkbox v-model:checked="form.dealerGift">有赠品</a-checkbox>
<a-input-number v-if="form.dealerGift" v-model:value="form.dealerGiftNum" style="width: 200px"
placeholder="请输入赠品数量"/>
</a-space>
<div class="ele-text-placeholder">经销商价格</div>
</a-form-item>
<a-form-item label="进货价" name="buyingPrice">
<a-form-item label="进货价" name="buyingPrice" v-if="!merchantId">
<a-space>
<a-input-number
:placeholder="`进货价`"
@@ -146,6 +159,75 @@
</a-space>
<div class="ele-text-placeholder">进货价</div>
</a-form-item>
<a-form-item label="连锁店价格" name="chainStorePrice" v-if="!merchantId">
<a-space>
<a-input-number
:placeholder="`请输入连锁店价格`"
:min="0.01"
style="width: 240px"
v-model:value="form.chainStorePrice"
/>
</a-space>
<div class="ele-text-placeholder">连锁店价格</div>
</a-form-item>
<a-form-item label="连锁店差价比例(%)" name="chainStoreRate" v-if="!merchantId">
<a-space>
<a-input-number
:placeholder="`请输入连锁店差价比例(%)`"
:min="0.01"
:max="100"
style="width: 240px"
v-model:value="form.chainStoreRate"
/>
</a-space>
<div class="ele-text-placeholder">连锁店差价比例(%)</div>
</a-form-item>
<a-form-item label="会员店价格" name="memberStorePrice" v-if="!merchantId">
<a-space>
<a-input-number
:placeholder="`请输入会员店价格`"
:min="0.01"
style="width: 240px"
v-model:value="form.memberStorePrice"
/>
</a-space>
<div class="ele-text-placeholder">会员店价格</div>
</a-form-item>
<a-form-item label="会员店差价比例(%)" name="memberStoreRate" v-if="!merchantId">
<a-space>
<a-input-number
:placeholder="`请输入会员店差价比例(%)`"
:min="0.01"
:max="100"
style="width: 240px"
v-model:value="form.memberStoreRate"
/>
</a-space>
<div class="ele-text-placeholder">会员店差价比例(%)</div>
</a-form-item>
<a-form-item label="会员超市价格" name="memberMarketPrice" v-if="!merchantId">
<a-space>
<a-input-number
:placeholder="`请输入会员超市价格`"
:min="0.01"
style="width: 240px"
v-model:value="form.memberMarketPrice"
/>
</a-space>
<div class="ele-text-placeholder">会员超市价格</div>
</a-form-item>
<a-form-item label="会员超市差价比例(%)" name="memberMarketRate" v-if="!merchantId">
<a-space>
<a-input-number
:placeholder="`请输入会员超市差价比例(%)`"
:min="0.01"
:max="100"
style="width: 240px"
v-model:value="form.memberMarketRate"
/>
</a-space>
<div class="ele-text-placeholder">会员超市差价比例(%)</div>
</a-form-item>
<a-form-item label="当前库存" name="stock">
<a-input-number
:placeholder="`商品库存`"
@@ -154,6 +236,9 @@
/>
<div class="ele-text-placeholder">划线价仅用于商品页展示</div>
</a-form-item>
<a-form-item label="是否新品">
<a-switch size="small" v-model:checked="form.isNew" :checked-value="1" :un-checked-value="0"/>
</a-form-item>
<a-form-item label="商品图片" name="image">
<SelectFile
:placeholder="`请选择视频文件`"
@@ -162,10 +247,9 @@
@done="chooseImage"
@del="onDeleteItem"
/>
<div class="ele-text-placeholder"
>支持上传视频mp4格式视频时长不超过60秒视频大小不超过200M
</div
>
<div class="ele-text-placeholder">
支持上传视频mp4格式视频时长不超过60秒视频大小不超过200M
</div>
</a-form-item>
<a-form-item label="轮播图" name="files">
<SelectFile
@@ -291,16 +375,16 @@
</a-form-item>
</a-tab-pane>
<a-tab-pane tab="商品详情" key="content">
<!-- <a-form-item label="视频">-->
<!-- <SelectFile-->
<!-- type="video"-->
<!-- :placeholder="`请选择商品视频`"-->
<!-- :limit="1"-->
<!-- :data="videos || []"-->
<!-- @done="chooseVideo"-->
<!-- @del="onDeleteVideo"-->
<!-- />-->
<!-- </a-form-item>-->
<!-- <a-form-item label="视频">-->
<!-- <SelectFile-->
<!-- type="video"-->
<!-- :placeholder="`请选择商品视频`"-->
<!-- :limit="1"-->
<!-- :data="videos || []"-->
<!-- @done="chooseVideo"-->
<!-- @del="onDeleteVideo"-->
<!-- />-->
<!-- </a-form-item>-->
<a-form-item name="content">
<!-- 编辑器 -->
<tinymce-editor
@@ -441,6 +525,11 @@ const columns = [
key: 'image',
align: 'center'
},
{
title: 'SKU',
dataIndex: 'sku',
align: 'center'
},
{
title: '售价',
dataIndex: 'salePrice',
@@ -488,13 +577,24 @@ const form = reactive<Goods>({
dealerPrice: undefined,
priceGift: undefined,
dealerGift: undefined,
priceGiftNum: undefined,
dealerGiftNum: undefined,
files: undefined,
sales: 0,
isNew: 0,
gainIntegral: 0,
goodsWeight: undefined,
recommend: undefined,
merchantId: undefined,
merchantName: undefined,
supplierMerchantId: undefined,
supplierName: undefined,
chainStorePrice: undefined,
memberStorePrice: undefined,
memberMarketPrice: undefined,
chainStoreRate: undefined,
memberStoreRate: undefined,
memberMarketRate: undefined,
stock: 1000,
deductStockType: 20,
isShow: 1,
@@ -589,6 +689,14 @@ const rules = reactive({
trigger: 'blur'
}
],
supplierMerchantId: [
{
required: true,
message: '请选择供应商',
type: 'number',
trigger: 'blur'
}
],
categoryId: [
{
required: true,
@@ -618,7 +726,32 @@ const rules = reactive({
type: 'number',
trigger: 'blur'
}
]
],
chainStorePrice: [
{
required: true,
message: '请输入连锁店价格',
type: 'number',
trigger: 'blur'
}
],
memberStorePrice: [
{
required: true,
message: '请输入会员店价格',
type: 'number',
trigger: 'blur'
}
],
memberMarketPrice: [
{
required: true,
message: '请输入会员超市价格',
type: 'number',
trigger: 'blur'
}
],
});
const onType = (index: number) => {
@@ -631,6 +764,11 @@ const chooseMerchantId = (item: Merchant) => {
form.merchantId = item.merchantId;
};
const chooseSupplier = (item: Merchant) => {
form.supplierName = item.merchantName;
form.supplierMerchantId = item.merchantId;
};
const chooseGoodsCategory = (item: GoodsCategory, value: any) => {
form.categoryId = value[1].value;
form.parentName = value[0].label;
@@ -866,6 +1004,8 @@ const save = () => {
.validate()
.then(() => {
loading.value = true;
if (form.priceGift && !form.priceGiftNum) return message.error('请输入会员赠品数量');
if (form.dealerGift && !form.dealerGiftNum) return message.error('请输入经销商赠品数量');
const formData = {
...form,
content: content.value,

View File

@@ -33,7 +33,18 @@
<a-tag v-if="record.type === 1">实物商品</a-tag>
</template>
<template v-if="column.key === 'image'">
<a-image :src="record.image" :width="80" />
<a-image :src="record.image" :width="80" v-if="!record.image.includes('.mp4')"/>
<div v-else class="flex justify-center items-center">
<div @click="open(record.image)" class="relative cursor-pointer w-[80px] h-80px">
<img
:src="record.image + '?x-oss-process=video/snapshot,t_2000,f_jpg,w_200,h_200'"
style="width: 80px; height: 80px"
/>
<div class="absolute" style="left: 30px; top: 30px">
<play-circle-outlined style="font-size: 20px; color:white"/>
</div>
</div>
</div>
</template>
<template v-if="column.key === 'salePrice'">
{{ formatNumber(record.salePrice) }}
@@ -44,24 +55,30 @@
color="green"
class="cursor-pointer"
@click="onUpdate(record)"
>出售中</a-tag
>出售中
</a-tag
>
<a-tag
v-if="record.isShow === 0"
color="red"
class="cursor-pointer"
@click="onUpdate(record)"
>已下架</a-tag
>已下架
</a-tag
>
</template>
<template v-if="column.key === 'status'">
<a-tag v-if="record.status === 0" color="green">显示</a-tag>
<a-tag v-if="record.status === 1" color="red">隐藏</a-tag>
</template>
<template v-if="column.key === 'isNew'">
<a-tag v-if="record.isNew === 1" color="green">新品</a-tag>
<a-tag v-else color="red">非新品</a-tag>
</template>
<template v-if="column.key === 'action'">
<a-space>
<a @click="openEdit(record)">修改</a>
<a-divider type="vertical" />
<a-divider type="vertical"/>
<a-popconfirm
title="确定要删除此记录吗?"
@confirm="remove(record)"
@@ -75,51 +92,48 @@
</a-card>
<!-- 编辑弹窗 -->
<GoodsEdit v-model:visible="showEdit" :data="current" @done="reload" />
<GoodsEdit v-model:visible="showEdit" :data="current" @done="reload"/>
</div>
</div>
</template>
<script lang="ts" setup>
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 type {
import {createVNode, ref, watch} from 'vue';
import {message, Modal} from 'ant-design-vue';
import {ExclamationCircleOutlined, PlayCircleOutlined} from '@ant-design/icons-vue';
import type {EleProTable} from 'ele-admin-pro';
import type {
DatasourceFunction,
ColumnItem
} from 'ele-admin-pro/es/ele-pro-table/types';
import Search from './components/search.vue';
import GoodsEdit from './components/goodsEdit.vue';
import {
} from 'ele-admin-pro/es/ele-pro-table/types';
import Search from './components/search.vue';
import GoodsEdit from './components/goodsEdit.vue';
import {
pageGoods,
removeGoods,
removeBatchGoods,
updateGoods
} from '@/api/shop/goods';
import type { Goods, GoodsParam } from '@/api/shop/goods/model';
import { formatNumber } from 'ele-admin-pro/es';
import router from '@/router';
import { openSpmUrl, openUrl } from '@/utils/common';
import { getSiteDomain } from '@/utils/domain';
import { getMerchantId } from '@/utils/merchant';
} from '@/api/shop/goods';
import type {Goods, GoodsParam} from '@/api/shop/goods/model';
import {formatNumber} from 'ele-admin-pro/es';
import router from '@/router';
import {openSpmUrl} from '@/utils/common';
import {getMerchantId} from '@/utils/merchant';
// 表格实例
const tableRef = ref<InstanceType<typeof EleProTable> | null>(null);
// 表格实例
const tableRef = ref<InstanceType<typeof EleProTable> | null>(null);
// 表格选中数据
const selection = ref<Goods[]>([]);
// 当前编辑数据
const current = ref<Goods | null>(null);
// 是否显示编辑弹窗
const showEdit = ref(false);
// 是否显示批量移动弹窗
const showMove = ref(false);
// 网站域名
const domain = getSiteDomain();
// 表格选中数据
const selection = ref<Goods[]>([]);
// 当前编辑数据
const current = ref<Goods | null>(null);
// 是否显示编辑弹窗
const showEdit = ref(false);
// 是否显示批量移动弹窗
const showMove = ref(false);
// 表格数据源
const datasource: DatasourceFunction = ({
// 表格数据源
const datasource: DatasourceFunction = ({
page,
limit,
where,
@@ -136,12 +150,12 @@
page,
limit
});
};
};
// 表格列配置
const columns = ref<ColumnItem[]>([
// 表格列配置
const columns = ref<ColumnItem[]>([
{
title: '22商品ID',
title: '商品ID',
dataIndex: 'goodsId',
key: 'goodsId',
align: 'center',
@@ -166,6 +180,13 @@
ellipsis: true,
align: 'center'
},
{
title: '供应商',
dataIndex: 'supplierName',
ellipsis: true,
align: 'center',
hideInTable: true
},
{
title: '商品编码',
dataIndex: 'code',
@@ -279,6 +300,12 @@
sorter: true,
align: 'center'
},
{
title: '是否新品',
dataIndex: 'isNew',
key: 'isNew',
align: 'center'
},
{
title: '排序号',
dataIndex: 'sortNumber',
@@ -303,35 +330,39 @@
align: 'center',
hideInSetting: true
}
]);
]);
/* 搜索 */
const reload = (where?: GoodsParam) => {
/* 搜索 */
const reload = (where?: GoodsParam) => {
selection.value = [];
tableRef?.value?.reload({ where: where });
};
tableRef?.value?.reload({where: where});
};
/* 打开编辑弹窗 */
const openEdit = (row?: Goods) => {
/* 打开编辑弹窗 */
const openEdit = (row?: Goods) => {
current.value = row ?? null;
showEdit.value = true;
};
};
/* 打开批量移动弹窗 */
const openMove = () => {
/* 打开批量移动弹窗 */
const openMove = () => {
showMove.value = true;
};
};
const onUpdate = (row?: Goods) => {
const open = (url?: string) => {
window.open(url);
};
const onUpdate = (row?: Goods) => {
const isShow = row?.isShow == 0 ? 1 : 0;
updateGoods({ ...row, isShow }).then((msg) => {
updateGoods({...row, isShow}).then((msg) => {
message.success(msg);
reload();
});
};
};
/* 删除单个 */
const remove = (row: Goods) => {
/* 删除单个 */
const remove = (row: Goods) => {
const hide = message.loading('请求中..', 0);
removeGoods(row.goodsId)
.then((msg) => {
@@ -343,10 +374,10 @@
hide();
message.error(e.message);
});
};
};
/* 批量删除 */
const removeBatch = () => {
/* 批量删除 */
const removeBatch = () => {
if (!selection.value.length) {
message.error('请至少选择一条数据');
return;
@@ -370,10 +401,10 @@
});
}
});
};
};
/* 自定义行属性 */
const customRow = (record: Goods) => {
/* 自定义行属性 */
const customRow = (record: Goods) => {
return {
// 行点击事件
onClick: () => {
@@ -384,9 +415,9 @@
openEdit(record);
}
};
};
};
watch(
watch(
() => router.currentRoute.value.params.id,
(id) => {
if (id && Number(id) > 0) {
@@ -394,14 +425,14 @@
}
reload();
},
{ immediate: true }
);
{immediate: true}
);
</script>
<script lang="ts">
export default {
export default {
name: 'Goods'
};
};
</script>
<style lang="less" scoped></style>

View File

@@ -151,6 +151,7 @@
parentId: undefined,
image: '',
status: 0,
type: undefined,
sortNumber: 100,
merchantId: getMerchantId()
});
@@ -222,7 +223,8 @@
...form,
// menuType 对应的值与后端不一致在前端处理
// menuType: form.menuType === 2 ? 1 : 0,
parentId: form.parentId || 0
parentId: form.parentId || 0,
type: getMerchantId() ? 1 : 0
};
const saveOrUpdate = isUpdate.value
? updateGoodsCategory

View File

@@ -214,7 +214,7 @@
// menuType 对应的值与后端不一致在前端处理
// menuType: form.menuType === 2 ? 1 : 0,
parentId: form.parentId || 0,
type: 1
// type: 1
};
const saveOrUpdate = isUpdate.value
? updateGoodsCategory

View File

@@ -44,6 +44,8 @@
<a-tag v-else-if="record.type === 2" color="orange">链接</a-tag>
</template>
<template v-else-if="column.key === 'title'">
<div class="flex justify-start items-center">
<div class="bg-gray-300 w-[30px]">
<a-avatar
:size="26"
shape="square"
@@ -51,18 +53,19 @@
style="margin-right: 10px"
v-if="record.image"
/>
</div>
<a
:href="`${domain}/product/${record.categoryId}`"
target="_blank"
>{{ record.title }}</a
>
>{{ record.title }}</a>
</div>
</template>
<template v-if="column.key === 'showIndex'">
<a-space @click="onShowIndex(record)">
<span v-if="record.showIndex === 1" class="ele-text-success"
><CheckOutlined
/></span>
<span v-else class="ele-text-placeholder"><CloseOutlined /></span>
<span v-else class="ele-text-placeholder"><CloseOutlined/></span>
</a-space>
</template>
<template v-if="column.key === 'recommend'">
@@ -70,7 +73,7 @@
<span v-if="record.recommend === 1" class="ele-text-success"
><CheckOutlined
/></span>
<span v-else class="ele-text-placeholder"><CloseOutlined /></span>
<span v-else class="ele-text-placeholder"><CloseOutlined/></span>
</a-space>
</template>
<template v-if="column.key === 'status'">
@@ -80,11 +83,13 @@
<template v-else-if="column.key === 'action'">
<a-space>
<a @click="openEdit(null, record.categoryId)">添加</a>
<a-divider type="vertical" />
<a @click="moveUp(record)">上移<ArrowUpOutlined /></a>
<a-divider type="vertical" />
<a-divider type="vertical"/>
<a @click="moveUp(record)">上移
<ArrowUpOutlined/>
</a>
<a-divider type="vertical"/>
<a @click="openEdit(record)">修改</a>
<a-divider type="vertical" />
<a-divider type="vertical"/>
<a-popconfirm
placement="topRight"
title="确定要删除此分类吗?"
@@ -100,7 +105,7 @@
<!-- 商城分类编辑弹窗 -->
<category-edit
v-model:visible="showEdit"
v-if="merchantId == 0"
v-if="!merchantId"
:data="current"
:parent-id="parentId"
:category-list="categoryData"
@@ -120,50 +125,50 @@
</template>
<script lang="ts" setup>
import { ref, watch } from 'vue';
import { message } from 'ant-design-vue/es';
import {
import {ref, watch} from 'vue';
import {message} from 'ant-design-vue/es';
import {
ArrowUpOutlined,
PlusOutlined,
CheckOutlined,
CloseOutlined
} from '@ant-design/icons-vue';
import type {
} from '@ant-design/icons-vue';
import type {
DatasourceFunction,
ColumnItem,
EleProTableDone
} from 'ele-admin-pro/es/ele-pro-table/types';
import {
} from 'ele-admin-pro/es/ele-pro-table/types';
import {
messageLoading,
toDateString,
isExternalLink,
toTreeData,
eachTreeData
} 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 {
} 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,
updateGoodsCategory
} from '@/api/shop/goodsCategory';
import type {
} from '@/api/shop/goodsCategory';
import type {
GoodsCategory,
GoodsCategoryParam
} from '@/api/shop/goodsCategory/model';
import { openNew, openPreview, openUrl } from '@/utils/common';
import { getSiteInfo } from '@/api/layout';
import router from '@/router';
import Search from './components/search.vue';
import { getSiteDomain } from '@/utils/domain';
import { getMerchantId } from "@/utils/merchant";
} from '@/api/shop/goodsCategory/model';
import {openNew, openPreview, openUrl} from '@/utils/common';
import {getSiteInfo} from '@/api/layout';
import router from '@/router';
import Search from './components/search.vue';
import {getSiteDomain} from '@/utils/domain';
import {getMerchantId} from "@/utils/merchant";
// 表格实例
const tableRef = ref<InstanceType<typeof EleProTable> | null>(null);
// 表格实例
const tableRef = ref<InstanceType<typeof EleProTable> | null>(null);
// 表格列配置
const columns = ref<ColumnItem[]>([
// 表格列配置
const columns = ref<ColumnItem[]>([
{
title: 'ID',
dataIndex: 'categoryId',
@@ -223,7 +228,7 @@
align: 'center',
width: 120,
showSorterTooltip: false,
customRender: ({ text }) => ['显示', '隐藏'][text]
customRender: ({text}) => ['显示', '隐藏'][text]
},
{
title: '创建时间',
@@ -231,7 +236,7 @@
showSorterTooltip: false,
ellipsis: true,
width: 180,
customRender: ({ text }) => toDateString(text)
customRender: ({text}) => toDateString(text)
},
{
title: '操作',
@@ -239,49 +244,49 @@
width: 200,
align: 'center'
}
]);
]);
// 当前编辑数据
const current = ref<GoodsCategory | null>(null);
// 是否显示编辑弹窗
const showEdit = ref(false);
// 上级分类id
const parentId = ref<number>();
// 分类数据
const categoryData = ref<GoodsCategory[]>([]);
// 表格展开的行
const expandedRowKeys = ref<number[]>([]);
const searchText = ref('');
const tenantId = ref<number>();
const merchantId = ref<number>();
// 网站域名
const domain = getSiteDomain();
// 当前编辑数据
const current = ref<GoodsCategory | null>(null);
// 是否显示编辑弹窗
const showEdit = ref(false);
// 上级分类id
const parentId = ref<number>();
// 分类数据
const categoryData = ref<GoodsCategory[]>([]);
// 表格展开的行
const expandedRowKeys = ref<number[]>([]);
const searchText = ref('');
const tenantId = ref<number>();
const merchantId = ref<number>();
// 网站域名
const domain = getSiteDomain();
getSiteInfo().then((data) => {
getSiteInfo().then((data) => {
tenantId.value = data.tenantId;
});
});
// 表格数据源
const datasource: DatasourceFunction = ({ where }) => {
// 表格数据源
const datasource: DatasourceFunction = ({where}) => {
where.title = searchText.value;
where.type = 0;
if (getMerchantId()) {
where.type = 1;
where.merchantId = getMerchantId();
}
return listGoodsCategory({ ...where });
};
return listGoodsCategory({...where});
};
const linkTo = (item: GoodsCategory) => {
const linkTo = (item: GoodsCategory) => {
if (item.children) {
return false;
}
const url = `http://${tenantId.value}.${domain.value}${item.path}`;
return openNew(url.replace(':id', String(item.categoryId)));
};
};
// 上移
const moveUp = (row?: GoodsCategory) => {
// 上移
const moveUp = (row?: GoodsCategory) => {
updateGoodsCategory({
categoryId: row?.categoryId,
sortNumber: Number(row?.sortNumber) - 1
@@ -289,38 +294,38 @@
message.success(msg);
reload();
});
};
};
/* 数据转为树形结构 */
const parseData = (data: GoodsCategory[]) => {
/* 数据转为树形结构 */
const parseData = (data: GoodsCategory[]) => {
return toTreeData({
data: data.map((d) => {
return { ...d, key: d.categoryId, value: d.categoryId };
return {...d, key: d.categoryId, value: d.categoryId};
}),
idField: 'categoryId',
parentIdField: 'parentId'
});
};
};
/* 表格渲染完成回调 */
const onDone: EleProTableDone<GoodsCategory> = ({ data }) => {
/* 表格渲染完成回调 */
const onDone: EleProTableDone<GoodsCategory> = ({data}) => {
categoryData.value = data;
};
};
/* 刷新表格 */
const reload = (where?: GoodsCategoryParam) => {
tableRef?.value?.reload({ where });
};
/* 刷新表格 */
const reload = (where?: GoodsCategoryParam) => {
tableRef?.value?.reload({where});
};
/* 打开编辑弹窗 */
const openEdit = (row?: GoodsCategory | null, id?: number) => {
/* 打开编辑弹窗 */
const openEdit = (row?: GoodsCategory | null, id?: number) => {
current.value = row ?? null;
parentId.value = id;
showEdit.value = true;
};
};
/* 删除单个 */
const remove = (row: GoodsCategory) => {
/* 删除单个 */
const remove = (row: GoodsCategory) => {
if (row.children?.length) {
message.error('请先删除子节点');
return;
@@ -336,10 +341,10 @@
hide();
message.error(e.message);
});
};
};
/* 展开全部 */
const expandAll = () => {
/* 展开全部 */
const expandAll = () => {
let keys: number[] = [];
eachTreeData(categoryData.value, (d) => {
if (d.children && d.children.length && d.categoryId) {
@@ -347,15 +352,15 @@
}
});
expandedRowKeys.value = keys;
};
};
/* 折叠全部 */
const foldAll = () => {
/* 折叠全部 */
const foldAll = () => {
expandedRowKeys.value = [];
};
};
/* 点击展开图标时触发 */
const onExpand = (expanded: boolean, record: GoodsCategory) => {
/* 点击展开图标时触发 */
const onExpand = (expanded: boolean, record: GoodsCategory) => {
if (expanded) {
expandedRowKeys.value = [
...expandedRowKeys.value,
@@ -366,14 +371,14 @@
(d) => d !== record.categoryId
);
}
};
};
/* 判断是否是目录 */
const isDirectory = (d: GoodsCategory) => {
/* 判断是否是目录 */
const isDirectory = (d: GoodsCategory) => {
return !!d.children?.length;
};
};
const onShowIndex = (row: GoodsCategory) => {
const onShowIndex = (row: GoodsCategory) => {
updateGoodsCategory({
...row,
showIndex: row.showIndex == 1 ? 0 : 1
@@ -381,9 +386,9 @@
message.success(msg);
reload();
});
};
};
const onRecommend = (row: GoodsCategory) => {
const onRecommend = (row: GoodsCategory) => {
updateGoodsCategory({
...row,
recommend: row.recommend == 1 ? 0 : 1
@@ -391,10 +396,10 @@
message.success(msg);
reload();
});
};
};
/* 自定义行属性 */
const customRow = (record: GoodsCategory) => {
/* 自定义行属性 */
const customRow = (record: GoodsCategory) => {
return {
// 行点击事件
onClick: () => {
@@ -405,20 +410,20 @@
openEdit(record);
}
};
};
};
watch(
watch(
() => router.currentRoute.value.params.id,
(id) => {
merchantId.value = Number(id);
reload();
},
{ immediate: true }
);
{immediate: true}
);
</script>
<script lang="ts">
export default {
export default {
name: 'GoodsCategory'
};
};
</script>

View File

@@ -0,0 +1,187 @@
<!-- 编辑弹窗 -->
<template>
<ele-modal
:width="800"
:visible="visible"
:maskClosable="false"
:maxable="maxable"
:title="isUpdate ? '编辑分润配置' : '添加分润配置'"
:body-style="{ paddingBottom: '28px' }"
@update:visible="updateVisible"
@ok="save"
>
<a-form
ref="formRef"
:model="form"
:rules="rules"
:label-col="styleResponsive ? { md: 4, sm: 5, xs: 24 } : { flex: '90px' }"
:wrapper-col="
styleResponsive ? { md: 19, sm: 19, xs: 24 } : { flex: '1' }
"
>
<a-form-item label="商品" name="goodsId">
<a-select v-model:value="form.goodsId" placeholder="请选择商品">
<a-select-option v-for="(item, index) in goodsList" :key="index" :value="item.goodsId">
{{ item.goodsName }}
</a-select-option>
</a-select>
</a-form-item>
<a-form-item label="店铺类型" name="merchantShopType">
<SelectMerchantType
:placeholder="`请选择店铺类型`"
v-model:value="form.merchantShopType"
@done="chooseShopType"
/>
</a-form-item>
<a-form-item label="SKU" v-if="form.goodsId && goodsList.find(v => v.goodsId === form.goodsId)?.goodsSkus">
<a-select v-model:value="form.skuId" placeholder="请选择SKU">
<a-select-option v-for="(item, index) in goodsList.find(v => v.goodsId === form.goodsId)?.goodsSkus" :key="index" :value="item.id">
{{ item.sku }}
</a-select-option>
</a-select>
</a-form-item>
<a-form-item label="比例(%)" name="rate">
<a-input-number style="width: 200px"
allow-clear
placeholder="请输入比例"
v-model:value="form.rate"
/>
</a-form-item>
</a-form>
</ele-modal>
</template>
<script lang="ts" setup>
import {ref, reactive, watch} from 'vue';
import {Form, message} from 'ant-design-vue';
import {assignObject, uuid} from 'ele-admin-pro';
import {addGoodsIncomeConfig, updateGoodsIncomeConfig} from '@/api/shop/goodsIncomeConfig';
import {GoodsIncomeConfig} from '@/api/shop/goodsIncomeConfig/model';
import {useThemeStore} from '@/store/modules/theme';
import {storeToRefs} from 'pinia';
import {ItemType} from 'ele-admin-pro/es/ele-image-upload/types';
import {FormInstance} from 'ant-design-vue/es/form';
import {MerchantType} from "@/api/shop/merchantType/model";
import {Goods} from "@/api/shop/goods/model";
import {listGoods} from "@/api/shop/goods";
// 是否是修改
const isUpdate = ref(false);
const useForm = Form.useForm;
// 是否开启响应式布局
const themeStore = useThemeStore();
const {styleResponsive} = storeToRefs(themeStore);
const props = defineProps<{
// 弹窗是否打开
visible: boolean;
// 修改回显的数据
data?: GoodsIncomeConfig | null;
}>();
const emit = defineEmits<{
(e: 'done'): void;
(e: 'update:visible', visible: boolean): void;
}>();
// 提交状态
const loading = ref(false);
// 是否显示最大化切换按钮
const maxable = ref(true);
// 表格选中数据
const formRef = ref<FormInstance | null>(null);
const images = ref<ItemType[]>([]);
// 用户信息
const form = reactive<GoodsIncomeConfig>({
id: undefined,
goodsId: undefined,
merchantShopType: undefined,
skuId: undefined,
rate: undefined,
userId: undefined,
comments: undefined,
sortNumber: undefined,
deleted: undefined,
tenantId: undefined,
updateTime: undefined,
createTime: undefined,
});
/* 更新visible */
const updateVisible = (value: boolean) => {
emit('update:visible', value);
};
// 表单验证规则
const rules = reactive({
goodsIncomeConfigName: [
{
required: true,
type: 'string',
message: '请填写分润配置名称',
trigger: 'blur'
}
]
});
const chooseShopType = (data: MerchantType) => {
form.merchantShopType = data.name;
};
const {resetFields} = useForm(form, rules);
/* 保存编辑 */
const save = () => {
if (!formRef.value) {
return;
}
formRef.value
.validate()
.then(() => {
loading.value = true;
const formData = {
...form
};
const saveOrUpdate = isUpdate.value ? updateGoodsIncomeConfig : addGoodsIncomeConfig;
saveOrUpdate(formData)
.then((msg) => {
loading.value = false;
message.success(msg);
updateVisible(false);
emit('done');
})
.catch((e) => {
loading.value = false;
message.error(e.message);
});
})
.catch(() => {
});
};
const goodsList = ref<Goods[]>([]);
const getGoodsList = async () => {
goodsList.value = await listGoods()
}
watch(
() => props.visible,
async (visible) => {
if (visible) {
await getGoodsList()
if (props.data) {
assignObject(form, props.data);
isUpdate.value = true;
} else {
isUpdate.value = false;
}
} else {
resetFields();
}
},
{immediate: true}
);
</script>

View File

@@ -0,0 +1,42 @@
<!-- 搜索表单 -->
<template>
<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-space>
</template>
<script lang="ts" setup>
import { PlusOutlined } from '@ant-design/icons-vue';
import type { GradeParam } from '@/api/user/grade/model';
import { watch } from 'vue';
const props = withDefaults(
defineProps<{
// 选中的角色
selection?: [];
}>(),
{}
);
const emit = defineEmits<{
(e: 'search', where?: GradeParam): void;
(e: 'add'): void;
(e: 'remove'): void;
(e: 'batchMove'): void;
}>();
// 新增
const add = () => {
emit('add');
};
watch(
() => props.selection,
() => {}
);
</script>

View File

@@ -0,0 +1,232 @@
<template>
<div class="page">
<div class="ele-body">
<a-card :bordered="false" :body-style="{ padding: '16px' }">
<ele-pro-table
ref="tableRef"
row-key="goodsIncomeConfigId"
:columns="columns"
:datasource="datasource"
:customRow="customRow"
tool-class="ele-toolbar-form"
class="sys-org-table"
>
<template #toolbar>
<search
@search="reload"
:selection="selection"
@add="openEdit"
@remove="removeBatch"
@batchMove="openMove"
/>
</template>
<template #bodyCell="{ column, record }">
<template v-if="column.key === 'image'">
<a-image :src="record.image" :width="50" />
</template>
<template v-if="column.key === 'status'">
<a-tag v-if="record.status === 0" color="green">显示</a-tag>
<a-tag v-if="record.status === 1" color="red">隐藏</a-tag>
</template>
<template v-if="column.key === 'action'">
<a-space>
<a @click="openEdit(record)">修改</a>
<a-divider type="vertical" />
<a-popconfirm
title="确定要删除此记录吗?"
@confirm="remove(record)"
>
<a class="ele-text-danger">删除</a>
</a-popconfirm>
</a-space>
</template>
</template>
</ele-pro-table>
</a-card>
<!-- 编辑弹窗 -->
<GoodsIncomeConfigEdit v-model:visible="showEdit" :data="current" @done="reload" />
</div>
</div>
</template>
<script lang="ts" setup>
import { createVNode, ref } 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
} from 'ele-admin-pro/es/ele-pro-table/types';
import Search from './components/search.vue';
import GoodsIncomeConfigEdit from './components/goodsIncomeConfigEdit.vue';
import { pageGoodsIncomeConfig, removeGoodsIncomeConfig, removeBatchGoodsIncomeConfig } from '@/api/shop/goodsIncomeConfig';
import type { GoodsIncomeConfig, GoodsIncomeConfigParam } from '@/api/shop/goodsIncomeConfig/model';
// 表格实例
const tableRef = ref<InstanceType<typeof EleProTable> | null>(null);
// 表格选中数据
const selection = ref<GoodsIncomeConfig[]>([]);
// 当前编辑数据
const current = ref<GoodsIncomeConfig | null>(null);
// 是否显示编辑弹窗
const showEdit = ref(false);
// 是否显示批量移动弹窗
const showMove = ref(false);
// 加载状态
const loading = ref(true);
// 表格数据源
const datasource: DatasourceFunction = ({
page,
limit,
where,
orders,
filters
}) => {
if (filters) {
where.status = filters.status;
}
return pageGoodsIncomeConfig({
...where,
...orders,
page,
limit
});
};
// 表格列配置
const columns = ref<ColumnItem[]>([
{
title: '商品',
dataIndex: ['goods', 'goodsName'],
key: 'goodsId',
align: 'center',
},
{
title: '店铺类型',
dataIndex: 'merchantShopType',
key: 'merchantShopType',
align: 'center',
},
{
title: 'SKU',
dataIndex: ['goodsSku', 'sku'],
key: 'spec',
align: 'center',
},
{
title: '比例(%)',
dataIndex: 'rate',
key: 'rate',
align: 'center',
},
{
title: '创建时间',
dataIndex: 'createTime',
key: 'createTime',
align: 'center',
sorter: true,
ellipsis: true,
customRender: ({ text }) => toDateString(text, 'yyyy-MM-dd')
},
{
title: '操作',
key: 'action',
width: 180,
fixed: 'right',
align: 'center',
hideInSetting: true
}
]);
/* 搜索 */
const reload = (where?: GoodsIncomeConfigParam) => {
selection.value = [];
tableRef?.value?.reload({ where: where });
};
/* 打开编辑弹窗 */
const openEdit = (row?: GoodsIncomeConfig) => {
current.value = row ?? null;
showEdit.value = true;
};
/* 打开批量移动弹窗 */
const openMove = () => {
showMove.value = true;
};
/* 删除单个 */
const remove = (row: GoodsIncomeConfig) => {
const hide = message.loading('请求中..', 0);
removeGoodsIncomeConfig(row.id)
.then((msg) => {
hide();
message.success(msg);
reload();
})
.catch((e) => {
hide();
message.error(e.message);
});
};
/* 批量删除 */
const removeBatch = () => {
if (!selection.value.length) {
message.error('请至少选择一条数据');
return;
}
Modal.confirm({
title: '提示',
content: '确定要删除选中的记录吗?',
icon: createVNode(ExclamationCircleOutlined),
maskClosable: true,
onOk: () => {
const hide = message.loading('请求中..', 0);
removeBatchGoodsIncomeConfig(selection.value.map((d) => d.goodsIncomeConfigId))
.then((msg) => {
hide();
message.success(msg);
reload();
})
.catch((e) => {
hide();
message.error(e.message);
});
}
});
};
/* 查询 */
const query = () => {
loading.value = true;
};
/* 自定义行属性 */
const customRow = (record: GoodsIncomeConfig) => {
return {
// 行点击事件
onClick: () => {
// console.log(record);
},
// 行双击事件
onDblclick: () => {
openEdit(record);
}
};
};
query();
</script>
<script lang="ts">
export default {
name: 'GoodsIncomeConfig'
};
</script>
<style lang="less" scoped></style>

View File

@@ -0,0 +1,161 @@
<!-- 编辑弹窗 -->
<template>
<ele-modal
:width="800"
:visible="visible"
:maskClosable="false"
:maxable="maxable"
:title="isUpdate ? '编辑商户商品库存' : '添加商户商品库存'"
:body-style="{ paddingBottom: '28px' }"
@update:visible="updateVisible"
@ok="save"
>
<a-form
ref="formRef"
:model="form"
:rules="rules"
:label-col="styleResponsive ? { md: 4, sm: 5, xs: 24 } : { flex: '90px' }"
:wrapper-col="
styleResponsive ? { md: 19, sm: 19, xs: 24 } : { flex: '1' }
"
>
<a-form-item label="商品" name="goodsId">
<a-select v-model:value="form.goodsId" placeholder="请选择商品" style="width: 100%">
<a-select-option v-for="(item, index) in goodsList" :value="item.goodsId" :key="index">{{
item.goodsName
}}
</a-select-option>
</a-select>
</a-form-item>
<a-form-item label="库存数量" name="stock">
<a-input
allow-clear
placeholder="请输入库存"
v-model:value="form.stock"
/>
</a-form-item>
</a-form>
</ele-modal>
</template>
<script lang="ts" setup>
import {ref, reactive, watch} from 'vue';
import {Form, message} from 'ant-design-vue';
import {assignObject} from 'ele-admin-pro';
import {addGoodsStockInMerchant, updateGoodsStockInMerchant} from '@/api/shop/goodsStockInMerchant';
import {GoodsStockInMerchant} from '@/api/shop/goodsStockInMerchant/model';
import {useThemeStore} from '@/store/modules/theme';
import {storeToRefs} from 'pinia';
import {FormInstance} from 'ant-design-vue/es/form';
import {Goods} from "@/api/shop/goods/model";
import {listGoods} from "@/api/shop/goods";
// 是否是修改
const isUpdate = ref(false);
const useForm = Form.useForm;
// 是否开启响应式布局
const themeStore = useThemeStore();
const {styleResponsive} = storeToRefs(themeStore);
const props = defineProps<{
// 弹窗是否打开
visible: boolean;
// 修改回显的数据
data?: GoodsStockInMerchant | null;
}>();
const emit = defineEmits<{
(e: 'done'): void;
(e: 'update:visible', visible: boolean): void;
}>();
// 提交状态
const loading = ref(false);
// 是否显示最大化切换按钮
const maxable = ref(true);
// 表格选中数据
const formRef = ref<FormInstance | null>(null);
// 用户信息
const form = reactive<GoodsStockInMerchant>({
id: undefined,
goodsId: undefined,
skuId: undefined,
num: undefined,
merchantId: undefined,
stock: undefined,
status: undefined,
comments: undefined,
sortNumber: undefined,
userId: undefined,
deleted: undefined,
tenantId: undefined,
createTime: undefined,
updateTime: undefined,
});
/* 更新visible */
const updateVisible = (value: boolean) => {
emit('update:visible', value);
};
// 表单验证规则
const rules = reactive({
});
const {resetFields} = useForm(form, rules);
/* 保存编辑 */
const save = () => {
if (!formRef.value) {
return;
}
formRef.value
.validate()
.then(() => {
loading.value = true;
const formData = {
...form
};
const saveOrUpdate = isUpdate.value ? updateGoodsStockInMerchant : addGoodsStockInMerchant;
saveOrUpdate(formData)
.then((msg) => {
loading.value = false;
message.success(msg);
updateVisible(false);
emit('done');
})
.catch((e) => {
loading.value = false;
message.error(e.message);
});
})
.catch(() => {
});
};
const goodsList = ref<Goods[]>([])
const getGoodsList = async () => {
goodsList.value = await listGoods()
}
watch(
() => props.visible,
async (visible) => {
if (visible) {
await getGoodsList()
if (props.data) {
assignObject(form, props.data);
isUpdate.value = true;
} else {
isUpdate.value = false;
}
} else {
resetFields();
}
},
{immediate: true}
);
</script>

View File

@@ -0,0 +1,42 @@
<!-- 搜索表单 -->
<template>
<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-space>
</template>
<script lang="ts" setup>
import { PlusOutlined } from '@ant-design/icons-vue';
import type { GradeParam } from '@/api/user/grade/model';
import { watch } from 'vue';
const props = withDefaults(
defineProps<{
// 选中的角色
selection?: [];
}>(),
{}
);
const emit = defineEmits<{
(e: 'search', where?: GradeParam): void;
(e: 'add'): void;
(e: 'remove'): void;
(e: 'batchMove'): void;
}>();
// 新增
const add = () => {
emit('add');
};
watch(
() => props.selection,
() => {}
);
</script>

View File

@@ -0,0 +1,230 @@
<template>
<div class="page">
<div class="ele-body">
<a-card :bordered="false" :body-style="{ padding: '16px' }">
<ele-pro-table
ref="tableRef"
row-key="goodsStockInMerchantId"
:columns="columns"
:datasource="datasource"
:customRow="customRow"
tool-class="ele-toolbar-form"
class="sys-org-table"
>
<template #toolbar>
<search
@search="reload"
:selection="selection"
@add="openEdit"
@remove="removeBatch"
@batchMove="openMove"
/>
</template>
<template #bodyCell="{ column, record }">
<template v-if="column.key === 'image'">
<a-image :src="record.image" :width="50"/>
</template>
<template v-if="column.key === 'status'">
<a-tag v-if="record.status === 0" color="green">显示</a-tag>
<a-tag v-if="record.status === 1" color="red">隐藏</a-tag>
</template>
<template v-if="column.key === 'action'">
<a-space>
<a @click="openEdit(record)">修改</a>
<a-divider type="vertical"/>
<a-popconfirm
title="确定要删除此记录吗?"
@confirm="remove(record)"
>
<a class="ele-text-danger">删除</a>
</a-popconfirm>
</a-space>
</template>
</template>
</ele-pro-table>
</a-card>
<!-- 编辑弹窗 -->
<GoodsStockInMerchantEdit v-model:visible="showEdit" :data="current" @done="reload"/>
</div>
</div>
</template>
<script lang="ts" setup>
import {createVNode, ref} 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
} from 'ele-admin-pro/es/ele-pro-table/types';
import Search from './components/search.vue';
import GoodsStockInMerchantEdit from './components/goodsStockInMerchantEdit.vue';
import {
pageGoodsStockInMerchant,
removeGoodsStockInMerchant,
removeBatchGoodsStockInMerchant
} from '@/api/shop/goodsStockInMerchant';
import type {GoodsStockInMerchant, GoodsStockInMerchantParam} from '@/api/shop/goodsStockInMerchant/model';
// 表格实例
const tableRef = ref<InstanceType<typeof EleProTable> | null>(null);
// 表格选中数据
const selection = ref<GoodsStockInMerchant[]>([]);
// 当前编辑数据
const current = ref<GoodsStockInMerchant | null>(null);
// 是否显示编辑弹窗
const showEdit = ref(false);
// 是否显示批量移动弹窗
const showMove = ref(false);
// 加载状态
const loading = ref(true);
// 表格数据源
const datasource: DatasourceFunction = ({
page,
limit,
where,
orders,
filters
}) => {
if (filters) {
where.status = filters.status;
}
return pageGoodsStockInMerchant({
...where,
...orders,
page,
limit
});
};
// 表格列配置
const columns = ref<ColumnItem[]>([
{
title: '商品',
dataIndex: ['goods', 'goodsName'],
key: 'goodsId',
align: 'center',
},
{
title: '库存',
dataIndex: 'stock',
key: 'stock',
align: 'center',
},
{
title: '创建时间',
dataIndex: 'createTime',
key: 'createTime',
align: 'center',
sorter: true,
ellipsis: true,
customRender: ({text}) => toDateString(text, 'yyyy-MM-dd')
},
{
title: '修改时间',
dataIndex: 'updateTime',
key: 'updateTime',
align: 'center',
},
{
title: '操作',
key: 'action',
width: 180,
fixed: 'right',
align: 'center',
hideInSetting: true
}
]);
/* 搜索 */
const reload = (where?: GoodsStockInMerchantParam) => {
selection.value = [];
tableRef?.value?.reload({where: where});
};
/* 打开编辑弹窗 */
const openEdit = (row?: GoodsStockInMerchant) => {
current.value = row ?? null;
showEdit.value = true;
};
/* 打开批量移动弹窗 */
const openMove = () => {
showMove.value = true;
};
/* 删除单个 */
const remove = (row: GoodsStockInMerchant) => {
const hide = message.loading('请求中..', 0);
removeGoodsStockInMerchant(row.goodsStockInMerchantId)
.then((msg) => {
hide();
message.success(msg);
reload();
})
.catch((e) => {
hide();
message.error(e.message);
});
};
/* 批量删除 */
const removeBatch = () => {
if (!selection.value.length) {
message.error('请至少选择一条数据');
return;
}
Modal.confirm({
title: '提示',
content: '确定要删除选中的记录吗?',
icon: createVNode(ExclamationCircleOutlined),
maskClosable: true,
onOk: () => {
const hide = message.loading('请求中..', 0);
removeBatchGoodsStockInMerchant(selection.value.map((d) => d.goodsStockInMerchantId))
.then((msg) => {
hide();
message.success(msg);
reload();
})
.catch((e) => {
hide();
message.error(e.message);
});
}
});
};
/* 查询 */
const query = () => {
loading.value = true;
};
/* 自定义行属性 */
const customRow = (record: GoodsStockInMerchant) => {
return {
// 行点击事件
onClick: () => {
// console.log(record);
},
// 行双击事件
onDblclick: () => {
openEdit(record);
}
};
};
query();
</script>
<script lang="ts">
export default {
name: 'GoodsStockInMerchant'
};
</script>
<style lang="less" scoped></style>

View File

@@ -114,6 +114,9 @@
v-model:value="form.commission"
/>
</a-form-item>
<a-form-item label="营业时间" required>
<a-time-range-picker format="HH:mm" value-format="HH:mm" v-model:value="timeRange"/>
</a-form-item>
<a-form-item label="关键字" name="keywords">
<a-select
v-model:value="form.keywords"
@@ -146,6 +149,14 @@
@update:checked="updateRecommend"
/>
</a-form-item>
<a-form-item label="是否在营业" name="recommend">
<a-switch
checked-children=""
un-checked-children=""
:checked="form.isOn === 1"
@update:checked="updateIsOn"
/>
</a-form-item>
<a-form-item label="是否需要审核" name="goodsReview">
<a-switch
checked-children=""
@@ -205,7 +216,6 @@ import {FileRecord} from '@/api/system/file/model';
import {MerchantType} from '@/api/shop/merchantType/model';
import {CenterPoint} from 'ele-admin-pro/es/ele-map-picker/types';
import {listRoles} from '@/api/system/role';
import {getTenantId} from '@/utils/domain';
import {MerchantCategory} from "@/api/shop/merchantCategory/model";
import {listMerchantCategory} from "@/api/shop/merchantCategory";
@@ -262,6 +272,9 @@ const form = reactive<Merchant>({
files: undefined,
ownStore: undefined,
recommend: undefined,
isOn: 1,
startTime: undefined,
endTime: undefined,
goodsReview: 1,
comments: '',
adminUrl: '',
@@ -414,6 +427,10 @@ const updateRecommend = (value: boolean) => {
form.recommend = value ? 1 : 0;
};
const updateIsOn = (value: boolean) => {
form.isOn = value ? 1 : 0;
};
const updateGoodsReview = (value: boolean) => {
form.goodsReview = value ? 1 : 0;
};
@@ -422,6 +439,8 @@ const onIndustry = (item: any) => {
form.category = item[0] + '/' + item[1];
};
const timeRange = ref<string[]>([])
const {resetFields} = useForm(form, rules);
/* 保存编辑 */
@@ -434,11 +453,16 @@ const save = () => {
.validate()
.then(() => {
loading.value = true;
if (!timeRange.value || !timeRange.value.length) {
return message.error('营业时间不能为空')
}
const formData = {
...form,
keywords: JSON.stringify(form.keywords),
files: JSON.stringify(files.value)
};
formData.startTime = timeRange.value[0];
formData.endTime = timeRange.value[1];
const saveOrUpdate = isUpdate.value ? updateMerchant : addMerchant;
saveOrUpdate(formData)
.then((msg) => {

View File

@@ -22,16 +22,35 @@
</template>
<template #bodyCell="{ column, record }">
<template v-if="column.key === 'image'">
<a-image :src="record.image" :width="50" />
<a-image :src="record.image" :width="50"/>
</template>
<template v-if="column.key === 'timeRange'">
<span v-if="record.startTime && record.endTime">{{ `${record.startTime}~${record.endTime}` }}</span>
</template>
<template v-if="column.key === 'status'">
<a-tag v-if="record.status === 0" color="green">显示</a-tag>
<a-tag v-if="record.status === 1" color="red">隐藏</a-tag>
</template>
<template v-if="column.key === 'canExpress'">
<a-tag class="cursor-pointer" v-if="record.canExpress === 1" color="green"
@click="changeFiled(record.merchantId, 'canExpress', 0)">可以
</a-tag>
<a-tag class="cursor-pointer" v-if="record.canExpress === 0" color="red"
@click="changeFiled(record.merchantId, 'canExpress', 1)">不可以
</a-tag>
</template>
<template v-if="column.key === 'isOn'">
<a-tag class="cursor-pointer" v-if="record.isOn === 1" color="green"
@click="changeFiled(record.merchantId, 'isOn', 0)">营业
</a-tag>
<a-tag class="cursor-pointer" v-if="record.isOn === 0" color="red"
@click="changeFiled(record.merchantId, 'isOn', 1)">闭店
</a-tag>
</template>
<template v-if="column.key === 'action'">
<a-space>
<a @click="openEdit(record)">修改</a>
<a-divider type="vertical" />
<a-divider type="vertical"/>
<a-popconfirm
v-if="!merchantId"
title="确定要删除此记录吗?"
@@ -46,48 +65,48 @@
</a-card>
<!-- 编辑弹窗 -->
<MerchantEdit v-model:visible="showEdit" :data="current" @done="reload" />
<MerchantEdit v-model:visible="showEdit" :data="current" @done="reload"/>
</div>
</div>
</template>
<script lang="ts" setup>
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 {
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
} from 'ele-admin-pro/es/ele-pro-table/types';
import Search from './components/search.vue';
import MerchantEdit from './components/merchantEdit.vue';
import {
} from 'ele-admin-pro/es/ele-pro-table/types';
import Search from './components/search.vue';
import MerchantEdit from './components/merchantEdit.vue';
import {
pageMerchant,
removeMerchant,
removeBatchMerchant
} from '@/api/shop/merchant';
import type { Merchant, MerchantParam } from '@/api/shop/merchant/model';
import { getMerchantId, openUrl } from "@/utils/common";
import router from '@/router';
removeBatchMerchant, updateMerchant
} from '@/api/shop/merchant';
import type {Merchant, MerchantParam} from '@/api/shop/merchant/model';
import {getMerchantId} from "@/utils/common";
import router from '@/router';
// 表格实例
const tableRef = ref<InstanceType<typeof EleProTable> | null>(null);
// 表格实例
const tableRef = ref<InstanceType<typeof EleProTable> | null>(null);
// 表格选中数据
const selection = ref<Merchant[]>([]);
// 当前编辑数据
const current = ref<Merchant | null>(null);
// 是否显示编辑弹窗
const showEdit = ref(false);
// 是否显示批量移动弹窗
const showMove = ref(false);
// 商户ID
const merchantId = getMerchantId();
// 表格选中数据
const selection = ref<Merchant[]>([]);
// 当前编辑数据
const current = ref<Merchant | null>(null);
// 是否显示编辑弹窗
const showEdit = ref(false);
// 是否显示批量移动弹窗
const showMove = ref(false);
// 商户ID
const merchantId = getMerchantId();
// 表格数据源
const datasource: DatasourceFunction = ({
// 表格数据源
const datasource: DatasourceFunction = ({
page,
limit,
where,
@@ -104,10 +123,10 @@
page,
limit
});
};
};
// 表格列配置
const columns = ref<ColumnItem[]>([
// 表格列配置
const columns = ref<ColumnItem[]>([
{
title: 'ID',
dataIndex: 'merchantId',
@@ -150,6 +169,21 @@
key: 'status',
align: 'center'
},
{
title: '是否可以发货',
key: 'canExpress',
align: 'center'
},
{
title: '是否营业',
key: 'isOn',
align: 'center'
},
{
title: '营业时间',
key: 'timeRange',
align: 'center'
},
{
title: '排序号',
dataIndex: 'sortNumber',
@@ -163,7 +197,7 @@
align: 'center',
sorter: true,
ellipsis: true,
customRender: ({ text }) => toDateString(text, 'yyyy-MM-dd')
customRender: ({text}) => toDateString(text, 'yyyy-MM-dd')
},
{
title: '操作',
@@ -173,27 +207,27 @@
align: 'center',
hideInSetting: true
}
]);
]);
/* 搜索 */
const reload = (where?: MerchantParam) => {
/* 搜索 */
const reload = (where?: MerchantParam) => {
selection.value = [];
tableRef?.value?.reload({ where: where });
};
tableRef?.value?.reload({where: where});
};
/* 打开编辑弹窗 */
const openEdit = (row?: Merchant) => {
/* 打开编辑弹窗 */
const openEdit = (row?: Merchant) => {
current.value = row ?? null;
showEdit.value = true;
};
};
/* 打开批量移动弹窗 */
const openMove = () => {
/* 打开批量移动弹窗 */
const openMove = () => {
showMove.value = true;
};
};
/* 删除单个 */
const remove = (row: Merchant) => {
/* 删除单个 */
const remove = (row: Merchant) => {
const hide = message.loading('请求中..', 0);
removeMerchant(row.merchantId)
.then((msg) => {
@@ -205,10 +239,10 @@
hide();
message.error(e.message);
});
};
};
/* 批量删除 */
const removeBatch = () => {
/* 批量删除 */
const removeBatch = () => {
if (!selection.value.length) {
message.error('请至少选择一条数据');
return;
@@ -232,10 +266,18 @@
});
}
});
};
};
/* 自定义行属性 */
const customRow = (record: Merchant) => {
const changeFiled = async (merchantId, field, value) => {
const data = {merchantId}
data[field] = value
await updateMerchant(data)
message.success('操作成功');
reload()
}
/* 自定义行属性 */
const customRow = (record: Merchant) => {
return {
// 行点击事件
onClick: () => {
@@ -246,9 +288,9 @@
openEdit(record);
}
};
};
};
watch(
watch(
() => router.currentRoute.value.params.id,
(id) => {
if (id) {
@@ -259,14 +301,14 @@
}
}
},
{ immediate: true }
);
{immediate: true}
);
</script>
<script lang="ts">
export default {
export default {
name: 'Merchant'
};
};
</script>
<style lang="less" scoped></style>

View File

@@ -34,6 +34,8 @@
<span class="ele-text-placeholder">{{ record.component }}</span>
</template>
<template v-else-if="column.key === 'title'">
<div class="flex justify-start items-center">
<div class="bg-gray-300 w-[30px]">
<a-avatar
:size="26"
shape="square"
@@ -41,11 +43,12 @@
style="margin-right: 10px"
v-if="record.image"
/>
</div>
<a
:href="`${domain}/product/${record.categoryId}`"
target="_blank"
>{{ record.title }}</a
>
>{{ record.title }}</a>
</div>
</template>
<template v-if="column.key === 'status'">
<a-tag v-if="record.status === 0" color="green">显示</a-tag>

View File

@@ -22,7 +22,9 @@
</template>
<template #bodyCell="{ column, record }">
<template v-if="column.key === 'image'">
<a-image :src="record.image" :width="50" />
<div class="bg-gray-300">
<a-image :src="record.image" :width="50"/>
</div>
</template>
<template v-if="column.key === 'status'">
<a-tag v-if="record.status === 0" color="green">显示</a-tag>
@@ -31,7 +33,7 @@
<template v-if="column.key === 'action'">
<a-space>
<a @click="openEdit(record)">修改</a>
<a-divider type="vertical" />
<a-divider type="vertical"/>
<a-popconfirm
title="确定要删除此记录吗?"
@confirm="remove(record)"
@@ -55,43 +57,43 @@
</template>
<script lang="ts" setup>
import { createVNode, ref } 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 {
import {createVNode, ref} 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
} from 'ele-admin-pro/es/ele-pro-table/types';
import Search from '../merchant/components/search.vue';
import MerchantTypeEdit from './components/merchantTypeEdit.vue';
import {
} from 'ele-admin-pro/es/ele-pro-table/types';
import Search from '../merchant/components/search.vue';
import MerchantTypeEdit from './components/merchantTypeEdit.vue';
import {
pageMerchantType,
removeMerchantType,
removeBatchMerchantType
} from '@/api/shop/merchantType';
import type {
} from '@/api/shop/merchantType';
import type {
MerchantType,
MerchantTypeParam
} from '@/api/shop/merchantType/model';
} from '@/api/shop/merchantType/model';
// 表格实例
const tableRef = ref<InstanceType<typeof EleProTable> | null>(null);
// 表格实例
const tableRef = ref<InstanceType<typeof EleProTable> | null>(null);
// 表格选中数据
const selection = ref<MerchantType[]>([]);
// 当前编辑数据
const current = ref<MerchantType | null>(null);
// 是否显示编辑弹窗
const showEdit = ref(false);
// 是否显示批量移动弹窗
const showMove = ref(false);
// 加载状态
const loading = ref(true);
// 表格选中数据
const selection = ref<MerchantType[]>([]);
// 当前编辑数据
const current = ref<MerchantType | null>(null);
// 是否显示编辑弹窗
const showEdit = ref(false);
// 是否显示批量移动弹窗
const showMove = ref(false);
// 加载状态
const loading = ref(true);
// 表格数据源
const datasource: DatasourceFunction = ({
// 表格数据源
const datasource: DatasourceFunction = ({
page,
limit,
where,
@@ -107,10 +109,10 @@
page,
limit
});
};
};
// 表格列配置
const columns = ref<ColumnItem[]>([
// 表格列配置
const columns = ref<ColumnItem[]>([
{
title: 'ID',
dataIndex: 'id',
@@ -158,27 +160,27 @@
align: 'center',
hideInSetting: true
}
]);
]);
/* 搜索 */
const reload = (where?: MerchantTypeParam) => {
/* 搜索 */
const reload = (where?: MerchantTypeParam) => {
selection.value = [];
tableRef?.value?.reload({ where: where });
};
tableRef?.value?.reload({where: where});
};
/* 打开编辑弹窗 */
const openEdit = (row?: MerchantType) => {
/* 打开编辑弹窗 */
const openEdit = (row?: MerchantType) => {
current.value = row ?? null;
showEdit.value = true;
};
};
/* 打开批量移动弹窗 */
const openMove = () => {
/* 打开批量移动弹窗 */
const openMove = () => {
showMove.value = true;
};
};
/* 删除单个 */
const remove = (row: MerchantType) => {
/* 删除单个 */
const remove = (row: MerchantType) => {
const hide = message.loading('请求中..', 0);
removeMerchantType(row.id)
.then((msg) => {
@@ -190,10 +192,10 @@
hide();
message.error(e.message);
});
};
};
/* 批量删除 */
const removeBatch = () => {
/* 批量删除 */
const removeBatch = () => {
if (!selection.value.length) {
message.error('请至少选择一条数据');
return;
@@ -217,15 +219,15 @@
});
}
});
};
};
/* 查询 */
const query = () => {
/* 查询 */
const query = () => {
loading.value = true;
};
};
/* 自定义行属性 */
const customRow = (record: MerchantType) => {
/* 自定义行属性 */
const customRow = (record: MerchantType) => {
return {
// 行点击事件
onClick: () => {
@@ -236,14 +238,14 @@
openEdit(record);
}
};
};
query();
};
query();
</script>
<script lang="ts">
export default {
export default {
name: 'MerchantType'
};
};
</script>
<style lang="less" scoped></style>

View File

@@ -18,66 +18,68 @@
styleResponsive ? { md: 19, sm: 19, xs: 24 } : { flex: '1' }
"
>
<a-form-item label="物流公司" name="expressName">
<SelectExpress
:placeholder="`选择物流公司`"
v-model:value="form.expressName"
@done="chooseExpressId"
/>
</a-form-item>
<a-form-item label="快递单号" name="expressNo">
<a-input
allow-clear
placeholder="快递单号"
v-model:value="form.expressNo"
/>
<a-form-item label="物流公司" name="expressId">
<a-select v-model:value="form.expressId" placeholder="点击选择物流公司">
<a-select-option v-for="(item, index) in expressList" :key="index" :value="item.expressId">
{{ item.expressName }}
</a-select-option>
</a-select>
</a-form-item>
<!-- <a-form-item label="快递单号" name="expressNo">-->
<!-- <a-input-->
<!-- allow-clear-->
<!-- placeholder="快递单号"-->
<!-- v-model:value="form.expressNo"-->
<!-- />-->
<!-- </a-form-item>-->
</a-form>
</ele-modal>
</template>
<script lang="ts" setup>
import { ref, reactive, watch } from 'vue';
import { Form, message } from 'ant-design-vue';
import { assignObject } from 'ele-admin-pro';
import { Order } from '@/api/shop/order/model';
import { useThemeStore } from '@/store/modules/theme';
import { storeToRefs } from 'pinia';
import { OrderDelivery } from '@/api/shop/orderDelivery/model';
import { Express } from '@/api/shop/express/model';
import {
addOrderDelivery,
updateOrderDelivery
} from '@/api/shop/orderDelivery';
import { FormInstance } from 'ant-design-vue/es/form';
import {ref, reactive, watch} from 'vue';
import {Form, message} from 'ant-design-vue';
import {assignObject} from 'ele-admin-pro';
import {Order} from '@/api/shop/order/model';
import {useThemeStore} from '@/store/modules/theme';
import {storeToRefs} from 'pinia';
// import { OrderDelivery } from '@/api/shop/orderDelivery/model';
import {Express} from '@/api/shop/express/model';
// import {
// addOrderDelivery,
// updateOrderDelivery
// } from '@/api/shop/orderDelivery';
import {FormInstance} from 'ant-design-vue/es/form';
import {listExpress} from "@/api/shop/express";
import {addOrderDelivery} from "@/api/shop/orderDelivery";
const useForm = Form.useForm;
const useForm = Form.useForm;
const props = defineProps<{
const props = defineProps<{
// 弹窗是否打开
visible: boolean;
// 修改回显的数据
data?: Order | null;
}>();
}>();
export interface step {
export interface step {
title?: String | undefined;
subTitle?: String | undefined;
description?: String | undefined;
}
}
// 是否是修改
const isUpdate = ref(false);
// 是否开启响应式布局
const themeStore = useThemeStore();
const { styleResponsive } = storeToRefs(themeStore);
// 是否是修改
const isUpdate = ref(false);
// 是否开启响应式布局
const themeStore = useThemeStore();
const {styleResponsive} = storeToRefs(themeStore);
// 表单验证规则
const rules = reactive({
expressName: [
// 表单验证规则
const rules = reactive({
expressId: [
{
required: true,
type: 'string',
type: 'number',
message: '请选择物流公司',
trigger: 'blur'
}
@@ -90,15 +92,15 @@
trigger: 'blur'
}
]
});
});
const emit = defineEmits<{
const emit = defineEmits<{
(e: 'done'): void;
(e: 'update:visible', visible: boolean): void;
}>();
}>();
// 订单信息
const form = reactive<OrderDelivery>({
// 订单信息
const form = reactive<OrderDeliver>({
deliveryId: undefined,
orderId: undefined,
deliveryMethod: undefined,
@@ -109,26 +111,26 @@
eorderHtml: undefined,
sortNumber: undefined,
tenantId: undefined
});
});
// 请求状态
const loading = ref(true);
// 表格选中数据
const formRef = ref<FormInstance | null>(null);
const { resetFields } = useForm(form, rules);
// 请求状态
const loading = ref(true);
// 表格选中数据
const formRef = ref<FormInstance | null>(null);
const {resetFields} = useForm(form, rules);
/* 更新visible */
const updateVisible = (value: boolean) => {
/* 更新visible */
const updateVisible = (value: boolean) => {
emit('update:visible', value);
};
};
const chooseExpressId = (data: Express) => {
form.expressName = data.expressName;
form.expressId = data.expressId;
};
const expressList = ref<Express[]>([])
const getExpressList = async () => {
expressList.value = await listExpress();
}
/* 保存编辑 */
const save = () => {
/* 保存编辑 */
const save = () => {
if (!formRef.value) {
return;
}
@@ -139,10 +141,7 @@
const formData = {
...form
};
const saveOrUpdate = isUpdate.value
? updateOrderDelivery
: addOrderDelivery;
saveOrUpdate(formData)
addOrderDelivery(formData)
.then((msg) => {
loading.value = false;
message.success(msg);
@@ -154,13 +153,15 @@
message.error(e.message);
});
})
.catch(() => {});
};
.catch(() => {
});
};
watch(
watch(
() => props.visible,
(visible) => {
if (visible) {
getExpressList()
if (props.data) {
loading.value = true;
assignObject(form, props.data);
@@ -169,5 +170,5 @@
resetFields();
}
}
);
);
</script>

View File

@@ -26,17 +26,29 @@
>
{{ form.orderNo }}
</a-descriptions-item>
<a-descriptions-item
label="物流方式"
:labelStyle="{ width: '90px', color: '#808080' }"
>
{{ form.deliveryType === 0 ? '快递' : '自提' }}
</a-descriptions-item>
<a-descriptions-item
label="订单状态"
:labelStyle="{ width: '90px', color: '#808080' }"
>
<a-tag v-if="form.orderStatus == 0">未使用</a-tag>
<a-tag v-if="form.orderStatus == 1">已付款</a-tag>
<a-tag v-if="form.orderStatus == 3">已取消</a-tag>
<a-tag v-if="form.orderStatus == 4">退款申请中</a-tag>
<a-tag v-if="form.orderStatus == 5">退款被拒绝</a-tag>
<a-tag v-if="form.orderStatus == 6">退款成功</a-tag>
<a-tag v-if="form.orderStatus == 7">客户端申请退款</a-tag>
<a-tag v-if="form.orderStatus === 0">未使用</a-tag>
<a-tag v-if="form.orderStatus === 1">已付款</a-tag>
<a-tag v-if="form.orderStatus === 3">已取消</a-tag>
<a-tag v-if="form.orderStatus === 4">退款申请中</a-tag>
<a-tag v-if="form.orderStatus === 5">退款被拒绝</a-tag>
<a-tag v-if="form.orderStatus === 6">退款成功</a-tag>
<a-tag v-if="form.orderStatus === 7">客户端申请退款</a-tag>
</a-descriptions-item>
<a-descriptions-item
label="订单类型"
:labelStyle="{ width: '90px', color: '#808080' }"
>
{{ ['商品', '外卖'][form?.type] }}
</a-descriptions-item>
<a-descriptions-item
label="买家信息"
@@ -78,25 +90,12 @@
label="支付方式"
:labelStyle="{ width: '90px', color: '#808080' }"
>
<template v-if="form.payStatus == 1">
<a-tag v-if="form.payType == 0">余额支付</a-tag>
<a-tag v-if="form.payType == 1">微信支付</a-tag>
<a-tag v-if="form.payType == 2">积分</a-tag>
<a-tag v-if="form.payType == 3">支付宝</a-tag>
<a-tag v-if="form.payType == 4">现金</a-tag>
<a-tag v-if="form.payType == 5">POS机</a-tag>
<a-tag v-if="form.payType == 6">VIP月卡</a-tag>
<a-tag v-if="form.payType == 7">formVIP年卡</a-tag>
<a-tag v-if="form.payType == 8">formVIP次卡</a-tag>
<a-tag v-if="form.payType == 9">formIC月卡</a-tag>
<a-tag v-if="form.payType == 10">formIC年卡</a-tag>
<a-tag v-if="form.payType == 11">formIC次卡</a-tag>
<a-tag v-if="form.payType == 12">form免费</a-tag>
<a-tag v-if="form.payType == 13">formVIP充值卡</a-tag>
<a-tag v-if="form.payType == 14">formIC充值卡</a-tag>
<a-tag v-if="form.payType == 15">form积分支付</a-tag>
<a-tag v-if="form.payType == 16">formVIP季卡</a-tag>
<a-tag v-if="form.payType == 17">formIC季卡</a-tag>
<template v-if="form.payStatus === 1">
<a-tag v-if="form.payType === 0">余额支付</a-tag>
<a-tag v-if="form.payType === 1">微信支付</a-tag>
<a-tag v-if="form.payType === 2">积分</a-tag>
<a-tag v-if="form.payType === 3">支付宝</a-tag>
<a-tag v-if="form.payType === 18">代付</a-tag>
</template>
<template v-else>
<span></span>
@@ -106,14 +105,23 @@
label="支付状态"
:labelStyle="{ width: '90px', color: '#808080' }"
>
<a-tag v-if="form.payStatus == 1" color="green"
><CheckOutlined class="tag-icon" />已付款</a-tag
<a-tag v-if="form.payStatus === 1" color="green"
>
<a-tag v-if="form.payStatus == 0" color="error"
><CloseOutlined class="tag-icon" />未付款</a-tag
<CheckOutlined class="tag-icon"/>
已付款
</a-tag
>
<a-tag v-if="form.payStatus == 3" color="cyan"
><CoffeeOutlined class="tag-icon" />未付款,占场中</a-tag
<a-tag v-if="form.payStatus === 0" color="error"
>
<CloseOutlined class="tag-icon"/>
未付款
</a-tag
>
<a-tag v-if="form.payStatus === 3" color="cyan"
>
<CoffeeOutlined class="tag-icon"/>
未付款,占场中
</a-tag
>
</a-descriptions-item>
<a-descriptions-item
@@ -136,6 +144,95 @@
</a-descriptions-item>
</a-descriptions>
</a-card>
<a-card class="order-card" :bordered="false" v-if="form && form.type === 0 && form.deliveryType === 0 && form.orderDelivery">
<a-descriptions title="物流信息" :column="3">
<a-descriptions-item
label="发货店铺"
:labelStyle="{ width: '90px', color: '#808080' }"
>
{{ form.expressMerchantName }}
</a-descriptions-item>
<a-descriptions-item
label="物流公司"
:labelStyle="{ width: '90px', color: '#808080' }"
>
{{ form.orderDelivery?.express?.expressName }}
</a-descriptions-item>
<a-descriptions-item
label="物流单号"
:labelStyle="{ width: '90px', color: '#808080' }"
>
{{ form.orderDelivery?.expressNo }}
</a-descriptions-item>
<a-descriptions-item
label="发货时间"
:labelStyle="{ width: '90px', color: '#808080' }"
>
{{ form.orderDelivery?.createTime }}
</a-descriptions-item>
</a-descriptions>
</a-card>
<a-card class="order-card" :bordered="false" v-if="form && form.type === 0 && form.deliveryType === 1 && form.selfTakeMerchant">
<a-descriptions title="自提信息" :column="3">
<a-descriptions-item
label="自提店铺"
:labelStyle="{ width: '90px', color: '#808080' }"
>
{{ form.selfTakeMerchant.merchantName }}
</a-descriptions-item>
<a-descriptions-item
label="店铺地址"
:labelStyle="{ width: '90px', color: '#808080' }"
>
{{ form.selfTakeMerchant.province }}{{ form.selfTakeMerchant.city }}{{
form.selfTakeMerchant.region
}}{{ form.selfTakeMerchant.address }}
</a-descriptions-item>
<a-descriptions-item
label="联系方式"
:labelStyle="{ width: '90px', color: '#808080' }"
>
{{ form.selfTakeMerchant.phone }}
</a-descriptions-item>
</a-descriptions>
</a-card>
<a-card class="order-card" :bordered="false" v-if="form && form.type === 1">
<a-descriptions title="门店信息" :column="3">
<a-descriptions-item
label="名称"
:labelStyle="{ width: '90px', color: '#808080' }"
>
{{ form?.merchant?.merchantName }}
</a-descriptions-item>
<a-descriptions-item
label="店铺地址"
:labelStyle="{ width: '90px', color: '#808080' }"
>
{{ form?.merchant?.province }}{{ form?.merchant?.city }}{{
form?.merchant?.region
}}{{ form?.merchant?.address }}
</a-descriptions-item>
<a-descriptions-item
label="联系方式"
:labelStyle="{ width: '90px', color: '#808080' }"
>
{{ form?.merchant?.phone }}
</a-descriptions-item>
<a-descriptions-item
label="配送时间"
:labelStyle="{ width: '90px', color: '#808080' }"
>
{{ form.sendStartTime }}~{{ form.sendEndTime }}
</a-descriptions-item>
<a-descriptions-item v-if="form.orderStatus === 1"
label="是否已收到赠品"
:labelStyle="{ width: '90px', color: '#808080' }"
>
<a-tag v-if="form.hasTakeGift === 1" color="green">已收到</a-tag>
<a-tag v-if="form.hasTakeGift === 0" color="red">未收到</a-tag>
</a-descriptions-item>
</a-descriptions>
</a-card>
<a-card class="order-card" :bordered="false">
<a-spin :spinning="loading">
<a-table
@@ -152,7 +249,7 @@
>
<template #bodyCell="{ column, record }">
<template v-if="column.key === 'goodsName'">
<a-avatar :src="record.image" :size="40" />
<a-avatar :src="record.image" :size="40"/>
<span style="margin-left: 8px">{{ record.goodsName }}</span>
</template>
</template>
@@ -163,42 +260,41 @@
</template>
<script lang="ts" setup>
import { ref, reactive, watch } from 'vue';
import { Form } from 'ant-design-vue';
import { assignObject } from 'ele-admin-pro';
import { Order } from '@/api/shop/order/model';
import { ColumnItem } from 'ele-admin-pro/es/ele-pro-table/types';
import {
import {ref, reactive, watch} from 'vue';
import {Form} from 'ant-design-vue';
import {assignObject} from 'ele-admin-pro';
import {Order} from '@/api/shop/order/model';
import {ColumnItem} from 'ele-admin-pro/es/ele-pro-table/types';
import {
CheckOutlined,
CloseOutlined,
CoffeeOutlined
} from '@ant-design/icons-vue';
import { pageOrderInfo } from '@/api/shop/orderInfo';
import { pageOrderGoods } from '@/api/shop/orderGoods';
import record from "@/views/cms/design/record/index.vue";
} from '@ant-design/icons-vue';
import {pageOrderInfo} from '@/api/shop/orderInfo';
import {pageOrderGoods} from '@/api/shop/orderGoods';
const useForm = Form.useForm;
const useForm = Form.useForm;
const props = defineProps<{
const props = defineProps<{
// 弹窗是否打开
visible: boolean;
// 修改回显的数据
data?: Order | null;
}>();
}>();
export interface step {
export interface step {
title?: String | undefined;
subTitle?: String | undefined;
description?: String | undefined;
}
}
// 是否是修改
const isUpdate = ref(false);
// 是否显示最大化切换按钮
const maxAble = ref(true);
// 是否是修改
const isUpdate = ref(false);
// 是否显示最大化切换按钮
const maxAble = ref(true);
// 步骤条
const steps = ref<step[]>([
// 步骤条
const steps = ref<step[]>([
{
title: '报餐',
description: undefined
@@ -219,16 +315,16 @@
title: '完成',
description: undefined
}
]);
const active = ref(2);
]);
const active = ref(2);
const emit = defineEmits<{
const emit = defineEmits<{
(e: 'done'): void;
(e: 'update:visible', visible: boolean): void;
}>();
}>();
// 订单信息
const form = reactive<Order>({
// 订单信息
const form = reactive<Order>({
orderId: undefined,
orderNo: undefined,
transactionId: undefined,
@@ -269,21 +365,33 @@
updateTime: undefined,
comments: '',
sortNumber: 100,
deliveryType: undefined,
orderDelivery: undefined,
selfTakeMerchantId: undefined,
selfTakeMerchantName: undefined,
expressMerchantId: undefined,
expressMerchantName: undefined,
type: undefined,
sendStartTime: undefined,
sendEndTime: undefined,
merchant: undefined,
hasTakeGift: undefined,
orderGoods: [],
orderInfo: []
});
orderInfo: [],
selfTakeMerchant: undefined
});
// 请求状态
const loading = ref(true);
// 请求状态
const loading = ref(true);
const { resetFields } = useForm(form);
const {resetFields} = useForm(form);
/* 更新visible */
const updateVisible = (value: boolean) => {
/* 更新visible */
const updateVisible = (value: boolean) => {
emit('update:visible', value);
};
};
const columns = ref<ColumnItem[]>([
const columns = ref<ColumnItem[]>([
{
title: '场馆名称',
dataIndex: 'merchantName',
@@ -301,11 +409,11 @@
{
title: '金额',
dataIndex: 'price',
customRender: ({ text }) => '¥' + text
customRender: ({text}) => '¥' + text
}
]);
]);
const columnsGoods = ref<ColumnItem[]>([
const columnsGoods = ref<ColumnItem[]>([
{
title: '商品名称',
dataIndex: 'goodsName',
@@ -323,12 +431,12 @@
{
title: '金额',
dataIndex: 'price',
customRender: ({ text }) => '¥' + text
customRender: ({text}) => '¥' + text
}
]);
]);
/* 制作步骤条 */
const loadSteps = (order) => {
/* 制作步骤条 */
const loadSteps = (order) => {
steps.value = [];
steps.value.push({
title: '下单'
@@ -384,30 +492,31 @@
if (order.orderStatus == 20) {
active.value = 4;
}
};
};
// const getOrderInfo = () => {
// const orderId = props.data?.orderId;
// listOrderInfo({ orderId }).then((data) => {
// orderInfo.value = data.filter((d) => d.totalNum > 0);
// });
// };
// const getOrderInfo = () => {
// const orderId = props.data?.orderId;
// listOrderInfo({ orderId }).then((data) => {
// orderInfo.value = data.filter((d) => d.totalNum > 0);
// });
// };
/* 保存编辑 */
const save = () => {};
/* 保存编辑 */
const save = () => {
};
watch(
watch(
() => props.visible,
(visible) => {
if (visible) {
if (props.data) {
loading.value = true;
assignObject(form, props.data);
pageOrderGoods({ orderId: form.orderId }).then((res) => {
pageOrderGoods({orderId: form.orderId}).then((res) => {
form.orderGoods = res?.list;
loading.value = false;
});
pageOrderInfo({ oid: form.orderId }).then((res) => {
pageOrderInfo({oid: form.orderId}).then((res) => {
form.orderInfo = res?.list;
loading.value = false;
});
@@ -417,24 +526,28 @@
resetFields();
}
}
);
);
</script>
<style lang="less" scoped>
.order-card {
.order-card {
margin-bottom: 20px;
}
.ant-form-item {
}
.ant-form-item {
margin-bottom: 5px;
}
.order-info {
}
.order-info {
display: flex;
.info {
padding-left: 5px;
display: flex;
flex-direction: column;
}
}
.tag-icon {
}
.tag-icon {
padding-right: 6px;
}
}
</style>

View File

@@ -82,6 +82,7 @@
<a-tag v-if="record.payType == 17"
><IdcardOutlined class="tag-icon" />IC季卡</a-tag
>
<a-tag v-if="record.payType == 18">代付</a-tag>
</template>
<template v-else>
<span></span>
@@ -154,7 +155,7 @@
>未使用</span
>
<span v-if="record.orderStatus == 2" class="ele-text-placeholder"
>取消</span
>完成</span
>
<span v-if="record.orderStatus == 1" class="ele-text-success"
>已完成</span
@@ -186,11 +187,11 @@
</template>
<template v-if="column.key === 'action'">
<a-space>
<a @click="openEdit(record)">详情</a>
<template v-if="record.deliveryStatus === 10">
<a-divider type="vertical" />
<template v-if="record.type === 0 && record.deliveryStatus === 10 && record.deliveryType === 0 && record.payStatus === 1">
<a @click="openDelivery(record)">发货</a>
<a-divider type="vertical" />
</template>
<a @click="openEdit(record)">详情</a>
<a-divider type="vertical" />
<a-dropdown>
<a class="ant-dropdown-link" @click.prevent>
@@ -232,7 +233,6 @@
CheckOutlined,
CloseOutlined,
AlipayCircleOutlined,
EllipsisOutlined,
DownOutlined
} from '@ant-design/icons-vue';
@@ -356,24 +356,19 @@
align: 'center'
},
{
title: '优惠类型',
dataIndex: 'couponType',
key: 'couponType',
align: 'center'
},
{
title: '是否已开票',
dataIndex: 'isInvoice',
key: 'isInvoice',
align: 'center'
},
{
title: '类型',
title: '订单类型',
dataIndex: 'type',
key: 'type',
align: 'center',
customRender: ({ text }) =>
['商城订单', '客户预定', '俱乐部训练场', '活动订场'][text]
['商', '外卖'][text]
},
{
title: '物流类型',
dataIndex: 'deliveryType',
align: 'center',
customRender: ({ text }) =>
['快递/配送', '自提'][text]
},
// {
// title: '申请退款时间',

View File

@@ -0,0 +1,42 @@
<!-- 搜索表单 -->
<template>
<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-space>
</template>
<script lang="ts" setup>
import { PlusOutlined } from '@ant-design/icons-vue';
import type { GradeParam } from '@/api/user/grade/model';
import { watch } from 'vue';
const props = withDefaults(
defineProps<{
// 选中的角色
selection?: [];
}>(),
{}
);
const emit = defineEmits<{
(e: 'search', where?: GradeParam): void;
(e: 'add'): void;
(e: 'remove'): void;
(e: 'batchMove'): void;
}>();
// 新增
const add = () => {
emit('add');
};
watch(
() => props.selection,
() => {}
);
</script>

View File

@@ -0,0 +1,193 @@
<!-- 编辑弹窗 -->
<template>
<ele-modal
:width="800"
:visible="visible"
:maskClosable="false"
:maxable="maxable"
:title="isUpdate ? '编辑开屏广告' : '添加开屏广告'"
:body-style="{ paddingBottom: '28px' }"
@update:visible="updateVisible"
@ok="save"
>
<a-form
ref="formRef"
:model="form"
:rules="rules"
:label-col="styleResponsive ? { md: 4, sm: 5, xs: 24 } : { flex: '90px' }"
:wrapper-col="
styleResponsive ? { md: 19, sm: 19, xs: 24 } : { flex: '1' }
"
>
<a-form-item label="标题" name="title">
<a-input
allow-clear
placeholder="请输入标题"
v-model:value="form.title"
/>
</a-form-item>
<a-form-item
label="图片"
name="image">
<SelectFile
:placeholder="`请选择图片`"
:limit="1"
:data="images"
@done="chooseImage"
@del="onDeleteItem"
/>
</a-form-item>
<a-form-item label="跳转类型" name="jumpType">
<a-select v-model:value="form.jumpType" placeholder="请选择跳转类型">
<a-select-option v-for="item in SplashJumpType" :key="item" :value="item.value">
{{ item.label }}
</a-select-option>
</a-select>
</a-form-item>
<a-form-item label="跳转主键" name="jumpPk">
<a-input-number style="width: 200px;"
allow-clear
placeholder="请输入跳转主键"
v-model:value="form.jumpPk"
/>
</a-form-item>
<a-form-item label="排序">
<a-input-number style="width: 200px;"
allow-clear
placeholder="请输入排序"
v-model:value="form.sortNumber"
/>
</a-form-item>
</a-form>
</ele-modal>
</template>
<script lang="ts" setup>
import {ref, reactive, watch} from 'vue';
import {Form, message} from 'ant-design-vue';
import {assignObject, uuid} from 'ele-admin-pro';
import {addSplash, updateSplash} from '@/api/shop/splash';
import {Splash, SplashJumpType} from '@/api/shop/splash/model';
import {useThemeStore} from '@/store/modules/theme';
import {storeToRefs} from 'pinia';
import {ItemType} from 'ele-admin-pro/es/ele-image-upload/types';
import {FormInstance} from 'ant-design-vue/es/form';
import {FileRecord} from '@/api/system/file/model';
// 是否是修改
const isUpdate = ref(false);
const useForm = Form.useForm;
// 是否开启响应式布局
const themeStore = useThemeStore();
const {styleResponsive} = storeToRefs(themeStore);
const props = defineProps<{
// 弹窗是否打开
visible: boolean;
// 修改回显的数据
data?: Splash | null;
}>();
const emit = defineEmits<{
(e: 'done'): void;
(e: 'update:visible', visible: boolean): void;
}>();
// 提交状态
const loading = ref(false);
// 是否显示最大化切换按钮
const maxable = ref(true);
// 表格选中数据
const formRef = ref<FormInstance | null>(null);
const images = ref<ItemType[]>([]);
// 用户信息
const form = reactive<Splash>({
id: undefined,
title: undefined,
image: undefined,
jumpType: undefined,
jumpPk: undefined,
});
/* 更新visible */
const updateVisible = (value: boolean) => {
emit('update:visible', value);
};
// 表单验证规则
const rules = reactive({
title: [{required: true, message: '请输入标题', trigger: 'blur'}],
image: [{required: true, message: '请选择图片', trigger: 'blur'}],
});
const chooseImage = (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 {resetFields} = useForm(form, rules);
/* 保存编辑 */
const save = () => {
if (!formRef.value) {
return;
}
formRef.value
.validate()
.then(() => {
loading.value = true;
const formData = {
...form
};
const saveOrUpdate = isUpdate.value ? updateSplash : addSplash;
saveOrUpdate(formData)
.then((msg) => {
loading.value = false;
message.success(msg);
updateVisible(false);
emit('done');
})
.catch((e) => {
loading.value = false;
message.error(e.message);
});
})
.catch(() => {
});
};
watch(
() => props.visible,
(visible) => {
if (visible) {
images.value = [];
if (props.data) {
assignObject(form, props.data);
if (props.data.image) {
images.value.push({
uid: uuid(),
url: props.data.image,
status: 'done'
})
}
isUpdate.value = true;
} else {
isUpdate.value = false;
}
} else {
resetFields();
}
},
{immediate: true}
);
</script>

View File

@@ -0,0 +1,234 @@
<template>
<div class="page">
<div class="ele-body">
<a-card :bordered="false" :body-style="{ padding: '16px' }">
<ele-pro-table
ref="tableRef"
row-key="splashId"
:columns="columns"
:datasource="datasource"
:customRow="customRow"
tool-class="ele-toolbar-form"
class="sys-org-table"
>
<template #toolbar>
<search
@search="reload"
:selection="selection"
@add="openEdit"
@remove="removeBatch"
@batchMove="openMove"
/>
</template>
<template #bodyCell="{ column, record }">
<template v-if="column.key === 'image'">
<a-image :src="record.image" :width="50"/>
</template>
<template v-if="column.key === 'jumpType'">
<span v-if="record.jumpType"> {{
SplashJumpType.find(item => item.value === record.jumpType).label
}}</span>
</template>
<template v-if="column.key === 'action'">
<a-space>
<a @click="openEdit(record)">修改</a>
<a-divider type="vertical"/>
<a-popconfirm
title="确定要删除此记录吗?"
@confirm="remove(record)"
>
<a class="ele-text-danger">删除</a>
</a-popconfirm>
</a-space>
</template>
</template>
</ele-pro-table>
</a-card>
<!-- 编辑弹窗 -->
<SplashEdit v-model:visible="showEdit" :data="current" @done="reload"/>
</div>
</div>
</template>
<script lang="ts" setup>
import {createVNode, ref} 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
} from 'ele-admin-pro/es/ele-pro-table/types';
import Search from './components/search.vue';
import SplashEdit from './components/splashEdit.vue';
import {pageSplash, removeSplash, removeBatchSplash} from '@/api/shop/splash';
import {Splash, SplashJumpType, SplashParam} from '@/api/shop/splash/model';
// 表格实例
const tableRef = ref<InstanceType<typeof EleProTable> | null>(null);
// 表格选中数据
const selection = ref<Splash[]>([]);
// 当前编辑数据
const current = ref<Splash | null>(null);
// 是否显示编辑弹窗
const showEdit = ref(false);
// 是否显示批量移动弹窗
const showMove = ref(false);
// 加载状态
const loading = ref(true);
// 表格数据源
const datasource: DatasourceFunction = ({
page,
limit,
where,
orders,
filters
}) => {
if (filters) {
where.status = filters.status;
}
return pageSplash({
...where,
...orders,
page,
limit
});
};
// 表格列配置
const columns = ref<ColumnItem[]>([
{
title: 'ID',
dataIndex: 'id',
key: 'id',
align: 'center',
width: 90,
},
{
title: '标题',
dataIndex: 'title',
key: 'title',
align: 'center',
},
{
title: '图片',
dataIndex: 'image',
key: 'image',
align: 'center',
},
{
title: '跳转类型',
dataIndex: 'jumpType',
key: 'jumpType',
align: 'center',
},
{
title: '创建时间',
dataIndex: 'createTime',
key: 'createTime',
align: 'center',
sorter: true,
ellipsis: true,
customRender: ({text}) => toDateString(text, 'yyyy-MM-dd')
},
{
title: '操作',
key: 'action',
width: 180,
fixed: 'right',
align: 'center',
hideInSetting: true
}
]);
/* 搜索 */
const reload = (where?: SplashParam) => {
selection.value = [];
tableRef?.value?.reload({where: where});
};
/* 打开编辑弹窗 */
const openEdit = (row?: Splash) => {
current.value = row ?? null;
showEdit.value = true;
};
/* 打开批量移动弹窗 */
const openMove = () => {
showMove.value = true;
};
/* 删除单个 */
const remove = (row: Splash) => {
const hide = message.loading('请求中..', 0);
removeSplash(row.splashId)
.then((msg) => {
hide();
message.success(msg);
reload();
})
.catch((e) => {
hide();
message.error(e.message);
});
};
/* 批量删除 */
const removeBatch = () => {
if (!selection.value.length) {
message.error('请至少选择一条数据');
return;
}
Modal.confirm({
title: '提示',
content: '确定要删除选中的记录吗?',
icon: createVNode(ExclamationCircleOutlined),
maskClosable: true,
onOk: () => {
const hide = message.loading('请求中..', 0);
removeBatchSplash(selection.value.map((d) => d.splashId))
.then((msg) => {
hide();
message.success(msg);
reload();
})
.catch((e) => {
hide();
message.error(e.message);
});
}
});
};
/* 查询 */
const query = () => {
loading.value = true;
};
/* 自定义行属性 */
const customRow = (record: Splash) => {
return {
// 行点击事件
onClick: () => {
// console.log(record);
},
// 行双击事件
onDblclick: () => {
openEdit(record);
}
};
};
query();
</script>
<script lang="ts">
export default {
name: 'Splash'
};
</script>
<style lang="less" scoped></style>

View File

@@ -0,0 +1,42 @@
<!-- 搜索表单 -->
<template>
<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-space>
</template>
<script lang="ts" setup>
import { PlusOutlined } from '@ant-design/icons-vue';
import type { GradeParam } from '@/api/user/grade/model';
import { watch } from 'vue';
const props = withDefaults(
defineProps<{
// 选中的角色
selection?: [];
}>(),
{}
);
const emit = defineEmits<{
(e: 'search', where?: GradeParam): void;
(e: 'add'): void;
(e: 'remove'): void;
(e: 'batchMove'): void;
}>();
// 新增
const add = () => {
emit('add');
};
watch(
() => props.selection,
() => {}
);
</script>

View File

@@ -0,0 +1,227 @@
<!-- 编辑弹窗 -->
<template>
<ele-modal
:width="800"
:visible="visible"
:maskClosable="false"
:maxable="maxable"
:title="isUpdate ? '编辑轮播图' : '添加轮播图'"
:body-style="{ paddingBottom: '28px' }"
@update:visible="updateVisible"
@ok="save"
>
<a-spin :spinning="loading">
<a-form
ref="formRef"
:model="form"
:rules="rules"
:label-col="styleResponsive ? { md: 4, sm: 5, xs: 24 } : { flex: '90px' }"
:wrapper-col="
styleResponsive ? { md: 19, sm: 19, xs: 24 } : { flex: '1' }
"
>
<a-form-item label="所属页面" name="type">
<a-select v-model:value="form.type" placeholder="请选择所属页面">
<a-select-option v-for="(item, index) in SwiperType" :key="index" :value="item.value">
{{ item.label }}
</a-select-option>
</a-select>
</a-form-item>
<a-form-item
label="图片"
name="image">
<SelectFile
:placeholder="`请选择图片`"
:limit="1"
:data="images"
@done="chooseImage"
@del="onDeleteItem"
/>
</a-form-item>
<a-form-item label="跳转商品" name="jumpPk">
<a-select v-model:value="form.jumpPk" placeholder="请选择跳转商品">
<a-select-option v-for="(item, index) in goodsList" :key="index" :value="item.goodsId">
{{ item.goodsName }}
</a-select-option>
</a-select>
</a-form-item>
<a-form-item label="背景颜色">
<div
class=" w-10 h-10 rounded-full m-2 cursor-pointer border-2 border-solid flex justify-center items-center text-red-600"
:class="[form.color ? 'border-none' : 'border-red-300']"
:style="{backgroundColor: form.color ?? 'red'}"
>{{ form.color ? '' : '选色' }}
</div>
<span v-if="form.color" class="text-sm cursor-pointer" @click="form.color = ''">清除</span>
<Vue3ColorPicker v-model="form.color" mode="solid"
:showColorList="false" :showEyeDrop="false" type="RGBA"/>
</a-form-item>
<a-form-item label="排序号" name="sortNumber">
<a-input-number
:min="0"
:max="9999"
class="ele-fluid"
placeholder="请输入排序号"
v-model:value="form.sortNumber"
/>
</a-form-item>
</a-form>
</a-spin>
</ele-modal>
</template>
<script lang="ts" setup>
import {ref, reactive, watch} from 'vue';
import {Form, message} from 'ant-design-vue';
import {assignObject, uuid} from 'ele-admin-pro';
import {addSwiper, updateSwiper} from '@/api/shop/swiper';
import {Swiper, SwiperType} from '@/api/shop/swiper/model';
import {useThemeStore} from '@/store/modules/theme';
import {storeToRefs} from 'pinia';
import {ItemType} from 'ele-admin-pro/es/ele-image-upload/types';
import {FormInstance} from 'ant-design-vue/es/form';
import {FileRecord} from '@/api/system/file/model';
import {Goods} from "@/api/shop/goods/model";
import {listGoods} from "@/api/shop/goods";
import {Vue3ColorPicker} from "@cyhnkckali/vue3-color-picker";
// 是否是修改
const isUpdate = ref(false);
const useForm = Form.useForm;
// 是否开启响应式布局
const themeStore = useThemeStore();
const {styleResponsive} = storeToRefs(themeStore);
const props = defineProps<{
// 弹窗是否打开
visible: boolean;
// 修改回显的数据
data?: Swiper | null;
}>();
const emit = defineEmits<{
(e: 'done'): void;
(e: 'update:visible', visible: boolean): void;
}>();
// 提交状态
const loading = ref(false);
// 是否显示最大化切换按钮
const maxable = ref(true);
// 表格选中数据
const formRef = ref<FormInstance | null>(null);
const images = ref<ItemType[]>([]);
// 用户信息
const form = reactive<Swiper>({
id: undefined,
type: "会员商城",
image: undefined,
jumpType: 'goods',
jumpPk: undefined,
color: undefined,
comments: undefined,
sortNumber: undefined,
userId: undefined,
deleted: undefined,
tenantId: undefined,
createTime: undefined,
updateTime: undefined,
});
/* 更新visible */
const updateVisible = (value: boolean) => {
emit('update:visible', value);
};
// 表单验证规则
const rules = reactive({
swiperName: [
{
required: true,
type: 'string',
message: '请填写轮播图名称',
trigger: 'blur'
}
]
});
const chooseImage = (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 {resetFields} = useForm(form, rules);
/* 保存编辑 */
const save = () => {
if (!formRef.value) {
return;
}
formRef.value
.validate()
.then(() => {
loading.value = true;
const formData = {
...form
};
const saveOrUpdate = isUpdate.value ? updateSwiper : addSwiper;
saveOrUpdate(formData)
.then((msg) => {
loading.value = false;
message.success(msg);
updateVisible(false);
emit('done');
})
.catch((e) => {
loading.value = false;
message.error(e.message);
});
})
.catch(() => {
});
};
const goodsList = ref<Goods[]>([]);
const getGoodsList = async () => {
goodsList.value = await listGoods()
}
watch(
() => props.visible,
async (visible) => {
if (visible) {
images.value = [];
loading.value = true
await getGoodsList()
if (props.data) {
assignObject(form, props.data);
if (props.data.image) {
images.value.push({
uid: uuid(),
url: props.data.image,
status: 'done'
})
}
isUpdate.value = true;
} else {
isUpdate.value = false;
}
loading.value = false
console.log(form.color)
} else {
resetFields();
}
},
{immediate: true}
);
</script>

View File

@@ -0,0 +1,232 @@
<template>
<div class="page">
<div class="ele-body">
<a-card :bordered="false" :body-style="{ padding: '16px' }">
<ele-pro-table
ref="tableRef"
row-key="swiperId"
:columns="columns"
:datasource="datasource"
:customRow="customRow"
tool-class="ele-toolbar-form"
class="sys-org-table"
>
<template #toolbar>
<search
@search="reload"
:selection="selection"
@add="openEdit"
@remove="removeBatch"
@batchMove="openMove"
/>
</template>
<template #bodyCell="{ column, record }">
<template v-if="column.key === 'image'">
<a-image :src="record.image" :width="50" />
</template>
<template v-if="column.key === 'status'">
<a-tag v-if="record.status === 0" color="green">显示</a-tag>
<a-tag v-if="record.status === 1" color="red">隐藏</a-tag>
</template>
<template v-if="column.key === 'action'">
<a-space>
<a @click="openEdit(record)">修改</a>
<a-divider type="vertical" />
<a-popconfirm
title="确定要删除此记录吗?"
@confirm="remove(record)"
>
<a class="ele-text-danger">删除</a>
</a-popconfirm>
</a-space>
</template>
</template>
</ele-pro-table>
</a-card>
<!-- 编辑弹窗 -->
<SwiperEdit v-model:visible="showEdit" :data="current" @done="reload" />
</div>
</div>
</template>
<script lang="ts" setup>
import { createVNode, ref } 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
} from 'ele-admin-pro/es/ele-pro-table/types';
import Search from './components/search.vue';
import SwiperEdit from './components/swiperEdit.vue';
import { pageSwiper, removeSwiper, removeBatchSwiper } from '@/api/shop/swiper';
import {Swiper, SwiperParam, SwiperType} from '@/api/shop/swiper/model';
// 表格实例
const tableRef = ref<InstanceType<typeof EleProTable> | null>(null);
// 表格选中数据
const selection = ref<Swiper[]>([]);
// 当前编辑数据
const current = ref<Swiper | null>(null);
// 是否显示编辑弹窗
const showEdit = ref(false);
// 是否显示批量移动弹窗
const showMove = ref(false);
// 加载状态
const loading = ref(true);
// 表格数据源
const datasource: DatasourceFunction = ({
page,
limit,
where,
orders,
filters
}) => {
if (filters) {
where.status = filters.status;
}
return pageSwiper({
...where,
...orders,
page,
limit
});
};
// 表格列配置
const columns = ref<ColumnItem[]>([
{
title: '所属页面',
dataIndex: 'type',
key: 'type',
align: 'center'
},
{
title: '图片',
dataIndex: 'image',
key: 'image',
align: 'center',
},
{
title: '排序号',
dataIndex: 'sortNumber',
key: 'sortNumber',
align: 'center',
},
{
title: '创建时间',
dataIndex: 'createTime',
key: 'createTime',
align: 'center',
sorter: true,
ellipsis: true,
customRender: ({ text }) => toDateString(text, 'yyyy-MM-dd')
},
{
title: '修改时间',
dataIndex: 'updateTime',
key: 'updateTime',
align: 'center',
},
{
title: '操作',
key: 'action',
width: 180,
fixed: 'right',
align: 'center',
hideInSetting: true
}
]);
/* 搜索 */
const reload = (where?: SwiperParam) => {
selection.value = [];
tableRef?.value?.reload({ where: where });
};
/* 打开编辑弹窗 */
const openEdit = (row?: Swiper) => {
current.value = row ?? null;
showEdit.value = true;
};
/* 打开批量移动弹窗 */
const openMove = () => {
showMove.value = true;
};
/* 删除单个 */
const remove = (row: Swiper) => {
const hide = message.loading('请求中..', 0);
removeSwiper(row.swiperId)
.then((msg) => {
hide();
message.success(msg);
reload();
})
.catch((e) => {
hide();
message.error(e.message);
});
};
/* 批量删除 */
const removeBatch = () => {
if (!selection.value.length) {
message.error('请至少选择一条数据');
return;
}
Modal.confirm({
title: '提示',
content: '确定要删除选中的记录吗?',
icon: createVNode(ExclamationCircleOutlined),
maskClosable: true,
onOk: () => {
const hide = message.loading('请求中..', 0);
removeBatchSwiper(selection.value.map((d) => d.swiperId))
.then((msg) => {
hide();
message.success(msg);
reload();
})
.catch((e) => {
hide();
message.error(e.message);
});
}
});
};
/* 查询 */
const query = () => {
loading.value = true;
};
/* 自定义行属性 */
const customRow = (record: Swiper) => {
return {
// 行点击事件
onClick: () => {
// console.log(record);
},
// 行双击事件
onDblclick: () => {
openEdit(record);
}
};
};
query();
</script>
<script lang="ts">
export default {
name: 'Swiper'
};
</script>
<style lang="less" scoped></style>

View File

@@ -0,0 +1,42 @@
<!-- 搜索表单 -->
<template>
<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-space>
</template>
<script lang="ts" setup>
import { PlusOutlined } from '@ant-design/icons-vue';
import type { GradeParam } from '@/api/user/grade/model';
import { watch } from 'vue';
const props = withDefaults(
defineProps<{
// 选中的角色
selection?: [];
}>(),
{}
);
const emit = defineEmits<{
(e: 'search', where?: GradeParam): void;
(e: 'add'): void;
(e: 'remove'): void;
(e: 'batchMove'): void;
}>();
// 新增
const add = () => {
emit('add');
};
watch(
() => props.selection,
() => {}
);
</script>

View File

@@ -0,0 +1,186 @@
<!-- 编辑弹窗 -->
<template>
<ele-modal
:width="800"
:visible="visible"
:maskClosable="false"
:maxable="maxable"
:title="isUpdate ? '编辑我的收藏' : '添加我的收藏'"
:body-style="{ paddingBottom: '28px' }"
@update:visible="updateVisible"
@ok="save"
>
<a-form
ref="formRef"
:model="form"
:rules="rules"
:label-col="styleResponsive ? { md: 4, sm: 5, xs: 24 } : { flex: '90px' }"
:wrapper-col="
styleResponsive ? { md: 19, sm: 19, xs: 24 } : { flex: '1' }
"
>
<a-form-item label="0店铺1商品" name="type">
<a-input
allow-clear
placeholder="请输入0店铺1商品"
v-model:value="form.type"
/>
</a-form-item>
<a-form-item label="租户ID" name="tid">
<a-input
allow-clear
placeholder="请输入租户ID"
v-model:value="form.tid"
/>
</a-form-item>
<a-form-item label="用户ID" name="userId">
<a-input
allow-clear
placeholder="请输入用户ID"
v-model:value="form.userId"
/>
</a-form-item>
</a-form>
</ele-modal>
</template>
<script lang="ts" setup>
import { ref, reactive, watch } from 'vue';
import { Form, message } from 'ant-design-vue';
import { assignObject, uuid } from 'ele-admin-pro';
import { addUserCollection, updateUserCollection } from '@/api/shop/userCollection';
import { UserCollection } from '@/api/shop/userCollection/model';
import { useThemeStore } from '@/store/modules/theme';
import { storeToRefs } from 'pinia';
import { ItemType } from 'ele-admin-pro/es/ele-image-upload/types';
import { FormInstance } from 'ant-design-vue/es/form';
import { FileRecord } from '@/api/system/file/model';
// 是否是修改
const isUpdate = ref(false);
const useForm = Form.useForm;
// 是否开启响应式布局
const themeStore = useThemeStore();
const { styleResponsive } = storeToRefs(themeStore);
const props = defineProps<{
// 弹窗是否打开
visible: boolean;
// 修改回显的数据
data?: UserCollection | null;
}>();
const emit = defineEmits<{
(e: 'done'): void;
(e: 'update:visible', visible: boolean): void;
}>();
// 提交状态
const loading = ref(false);
// 是否显示最大化切换按钮
const maxable = ref(true);
// 表格选中数据
const formRef = ref<FormInstance | null>(null);
const images = ref<ItemType[]>([]);
// 用户信息
const form = reactive<UserCollection>({
id: undefined,
type: undefined,
tid: undefined,
userId: undefined,
tenantId: undefined,
createTime: undefined,
userCollectionId: undefined,
userCollectionName: '',
status: 0,
comments: '',
sortNumber: 100
});
/* 更新visible */
const updateVisible = (value: boolean) => {
emit('update:visible', value);
};
// 表单验证规则
const rules = reactive({
userCollectionName: [
{
required: true,
type: 'string',
message: '请填写我的收藏名称',
trigger: 'blur'
}
]
});
const chooseImage = (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 { resetFields } = useForm(form, rules);
/* 保存编辑 */
const save = () => {
if (!formRef.value) {
return;
}
formRef.value
.validate()
.then(() => {
loading.value = true;
const formData = {
...form
};
const saveOrUpdate = isUpdate.value ? updateUserCollection : addUserCollection;
saveOrUpdate(formData)
.then((msg) => {
loading.value = false;
message.success(msg);
updateVisible(false);
emit('done');
})
.catch((e) => {
loading.value = false;
message.error(e.message);
});
})
.catch(() => {});
};
watch(
() => props.visible,
(visible) => {
if (visible) {
images.value = [];
if (props.data) {
assignObject(form, props.data);
if(props.data.image){
images.value.push({
uid: uuid(),
url: props.data.image,
status: 'done'
})
}
isUpdate.value = true;
} else {
isUpdate.value = false;
}
} else {
resetFields();
}
},
{ immediate: true }
);
</script>

View File

@@ -0,0 +1,233 @@
<template>
<div class="page">
<div class="ele-body">
<a-card :bordered="false" :body-style="{ padding: '16px' }">
<ele-pro-table
ref="tableRef"
row-key="userCollectionId"
:columns="columns"
:datasource="datasource"
:customRow="customRow"
tool-class="ele-toolbar-form"
class="sys-org-table"
>
<template #toolbar>
<search
@search="reload"
:selection="selection"
@add="openEdit"
@remove="removeBatch"
@batchMove="openMove"
/>
</template>
<template #bodyCell="{ column, record }">
<template v-if="column.key === 'image'">
<a-image :src="record.image" :width="50" />
</template>
<template v-if="column.key === 'status'">
<a-tag v-if="record.status === 0" color="green">显示</a-tag>
<a-tag v-if="record.status === 1" color="red">隐藏</a-tag>
</template>
<template v-if="column.key === 'action'">
<a-space>
<a @click="openEdit(record)">修改</a>
<a-divider type="vertical" />
<a-popconfirm
title="确定要删除此记录吗?"
@confirm="remove(record)"
>
<a class="ele-text-danger">删除</a>
</a-popconfirm>
</a-space>
</template>
</template>
</ele-pro-table>
</a-card>
<!-- 编辑弹窗 -->
<UserCollectionEdit v-model:visible="showEdit" :data="current" @done="reload" />
</div>
</div>
</template>
<script lang="ts" setup>
import { createVNode, ref } 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
} from 'ele-admin-pro/es/ele-pro-table/types';
import Search from './components/search.vue';
import UserCollectionEdit from './components/userCollectionEdit.vue';
import { pageUserCollection, removeUserCollection, removeBatchUserCollection } from '@/api/shop/userCollection';
import type { UserCollection, UserCollectionParam } from '@/api/shop/userCollection/model';
// 表格实例
const tableRef = ref<InstanceType<typeof EleProTable> | null>(null);
// 表格选中数据
const selection = ref<UserCollection[]>([]);
// 当前编辑数据
const current = ref<UserCollection | null>(null);
// 是否显示编辑弹窗
const showEdit = ref(false);
// 是否显示批量移动弹窗
const showMove = ref(false);
// 加载状态
const loading = ref(true);
// 表格数据源
const datasource: DatasourceFunction = ({
page,
limit,
where,
orders,
filters
}) => {
if (filters) {
where.status = filters.status;
}
return pageUserCollection({
...where,
...orders,
page,
limit
});
};
// 表格列配置
const columns = ref<ColumnItem[]>([
{
title: '主键ID',
dataIndex: 'id',
key: 'id',
align: 'center',
width: 90,
},
{
title: '0店铺1商品',
dataIndex: 'type',
key: 'type',
align: 'center',
},
{
title: '租户ID',
dataIndex: 'tid',
key: 'tid',
align: 'center',
},
{
title: '用户ID',
dataIndex: 'userId',
key: 'userId',
align: 'center',
},
{
title: '注册时间',
dataIndex: 'createTime',
key: 'createTime',
align: 'center',
sorter: true,
ellipsis: true,
customRender: ({ text }) => toDateString(text, 'yyyy-MM-dd')
},
{
title: '操作',
key: 'action',
width: 180,
fixed: 'right',
align: 'center',
hideInSetting: true
}
]);
/* 搜索 */
const reload = (where?: UserCollectionParam) => {
selection.value = [];
tableRef?.value?.reload({ where: where });
};
/* 打开编辑弹窗 */
const openEdit = (row?: UserCollection) => {
current.value = row ?? null;
showEdit.value = true;
};
/* 打开批量移动弹窗 */
const openMove = () => {
showMove.value = true;
};
/* 删除单个 */
const remove = (row: UserCollection) => {
const hide = message.loading('请求中..', 0);
removeUserCollection(row.userCollectionId)
.then((msg) => {
hide();
message.success(msg);
reload();
})
.catch((e) => {
hide();
message.error(e.message);
});
};
/* 批量删除 */
const removeBatch = () => {
if (!selection.value.length) {
message.error('请至少选择一条数据');
return;
}
Modal.confirm({
title: '提示',
content: '确定要删除选中的记录吗?',
icon: createVNode(ExclamationCircleOutlined),
maskClosable: true,
onOk: () => {
const hide = message.loading('请求中..', 0);
removeBatchUserCollection(selection.value.map((d) => d.userCollectionId))
.then((msg) => {
hide();
message.success(msg);
reload();
})
.catch((e) => {
hide();
message.error(e.message);
});
}
});
};
/* 查询 */
const query = () => {
loading.value = true;
};
/* 自定义行属性 */
const customRow = (record: UserCollection) => {
return {
// 行点击事件
onClick: () => {
// console.log(record);
},
// 行双击事件
onDblclick: () => {
openEdit(record);
}
};
};
query();
</script>
<script lang="ts">
export default {
name: 'UserCollection'
};
</script>
<style lang="less" scoped></style>

View File

@@ -0,0 +1,53 @@
<!-- 搜索表单 -->
<template>
<a-space :size="10" style="flex-wrap: wrap">
<a-input-search
allow-clear
v-model:value="where.keywords"
placeholder="租户ID|域名"
@search="search"
@pressEnter="search"
/>
</a-space>
</template>
<script lang="ts" setup>
import { watch } from 'vue';
import useSearch from '@/utils/use-search';
import { DomainParam } from '@/api/system/domain/model';
const props = withDefaults(
defineProps<{
// 选中的角色
selection?: [];
}>(),
{}
);
const emit = defineEmits<{
(e: 'search', where?: DomainParam): void;
(e: 'add'): void;
(e: 'remove'): void;
(e: 'batchMove'): void;
}>();
// 新增
const add = () => {
emit('add');
};
/* 搜索 */
const search = () => {
emit('search', where);
};
// 表单数据
const { where } = useSearch<DomainParam>({
keywords: ''
});
watch(
() => props.selection,
() => {}
);
</script>

View File

@@ -28,7 +28,7 @@
/>
</a-form-item>
<!--微信支付-->
<template v-if="form.code == 1">
<template v-if="form.code === 1">
<a-form-item label="微信商户号类型" name="wechatType">
<a-radio-group v-model:value="form.wechatType">
<a-radio :value="0">