2 Commits

Author SHA1 Message Date
d688fcaafc 测试弹窗1 2025-09-29 17:10:37 +08:00
9208c29952 测试弹窗 2025-09-29 17:09:32 +08:00
144 changed files with 1427 additions and 8761 deletions

View File

@@ -89,9 +89,5 @@
},
"[jsonc]": {
"editor.defaultFormatter": "vscode.json-language-features"
},
"files.associations": {
"*.ttml": "xml",
"*.ttss": "css"
}
}

View File

@@ -2,28 +2,9 @@
基于 Vue3 + Vite5+ TypeScript5 + Element-Plus + Pinia 等主流技术栈构建
## ysk-utils 工具类包
安装
```
pnpm install ysk-utils
```
更新
```
pnpm update ysk-utils
```
vscode如果无代码提示
重启 VS Code 的 TypeScript 服务器
输入:
```TypeScript: Restart TS Server```
## 正式宝塔
<https://121.40.128.145:38279/mianban/>
<https://121.40.128.145:38279/>
chaozg
chaozg123

View File

@@ -66,8 +66,7 @@
"vue": "^3.5.13",
"vue-clipboard3": "^2.0.0",
"vue-i18n": "^11.1.0",
"vue-router": "^4.5.0",
"ysk-utils": "^1.0.5"
"vue-router": "^4.5.0"
},
"devDependencies": {
"@commitlint/cli": "^19.7.1",

View File

@@ -1,15 +1,18 @@
<template>
<el-config-provider :locale="locale" :size="size">
<!-- 开启水印 -->
<el-watermark :font="{ color: fontColor }" :content="watermarkEnabled ? defaultSettings.watermarkContent : ''"
:z-index="9999" class="wh-full">
<el-watermark
:font="{ color: fontColor }"
:content="watermarkEnabled ? defaultSettings.watermarkContent : ''"
:z-index="9999"
class="wh-full"
>
<router-view />
</el-watermark>
</el-config-provider>
</template>
<script setup lang="ts">
// test
import { useAppStore, useSettingsStore } from "@/store";
import defaultSettings from "@/settings";
import { ThemeEnum } from "@/enums/ThemeEnum";

View File

@@ -9,12 +9,6 @@ const MenuApi = {
method: "get",
});
},
getCashMenus() {
return request<any, CashMenu[]>({
url: `${baseURL}/list/cash`,
method: "get",
});
},
/**获取所有菜单 */
getList(data: getListRequest) {
return request<any, MenuVO[]>({
@@ -54,13 +48,6 @@ const MenuApi = {
};
export default MenuApi;
export interface CashMenu {
component?: null | string;
menuId: number;
name: null | string;
path?: null | string;
[property: string]: any;
}
/** RouteVO路由对象 */
export interface RouteVO {

View File

@@ -33,11 +33,11 @@ const RoleApi = {
});
},
// 获取角色对应的菜单id
getMenu(id: number, type: number = 0) {
getMenu(id: number) {
return request<any, any[]>({
url: `${baseURL}/menu`,
method: "get",
params: { id, type },
params: { id },
});
},
};

View File

@@ -10,19 +10,6 @@ const ShopApi = {
params: params,
});
},
getBranchList(params: PageQuery) {
return request<any, ShopInfoEditDTO[]>({
url: `${baseURL}/branchList`,
method: "get",
params: params,
});
},
getBranchChange(id: PageQuery) {
return request<any, ShopInfoEditDTO[]>({
url: `${baseURL}/change/${id}`,
method: "post",
});
},
add(data: ShopInfoEditDTO) {
return request<any, ShopInfoEditDTO>({
url: `${baseURL}`,
@@ -290,4 +277,4 @@ export interface ShopInfo {
tubeType?: number | null;
updateTime?: null | string;
[property: string]: any;
}
}

View File

@@ -1,54 +0,0 @@
import request from "@/utils/request";
import { Account_BaseUrl } from "@/api/config";
const baseURL = Account_BaseUrl + "/admin/shop/branch";
const ShopBranchApi = {
getList(params: any) {
return request<any>({
url: `${baseURL}/page`,
method: "get",
params
});
},
getDataSync(params: any) {
return request<any>({
url: `${baseURL}/get/dataSyncMethod`,
method: "get",
params
});
},
setDataSync(id: any) {
return request<any>({
url: `${baseURL}/setting/dataSyncMethod?dataSyncMethod=${id}`,
method: "post",
});
},
dataSync(id: any) {
return request<any>({
url: `${baseURL}/data/sync/enable?branchShopId=${id}`,
method: "post",
});
},
enable(id: any) {
return request<any>({
url: `${baseURL}/account/enable?branchShopId=${id}`,
method: "post",
});
},
disable(id: any) {
return request<any>({
url: `${baseURL}/account/disable?branchShopId=${id}`,
method: "post",
});
},
};
export interface Responseres {
code?: number | null;
data?: any;
msg?: null | string;
[property: string]: any;
}
export default ShopBranchApi;

View File

@@ -8,4 +8,3 @@ export const Account_BaseUrl = "account";
export const Order_BaseUrl = "order";
export const Product_BaseUrl = "product";
export const System_BaseUrl = "system";
export const Market_BaseUrl = "market";

View File

@@ -1,129 +0,0 @@
import request from "@/utils/request";
import {
Account_BaseUrl,
Product_BaseUrl,
Market_BaseUrl
} from "@/api/config";
// 获取分店列表
export function getBranchPage() {
return request({
url: `${Account_BaseUrl + "/admin/shop/branch/page"}`,
method: "get",
});
}
// 获取商品-列表
export function getProductList() {
return request({
url: `${Product_BaseUrl + "/admin/product/list"}`,
method: "get",
});
}
// 获取商品分类
export function getCategoryList() {
return request({
url: `${Product_BaseUrl + "/admin/prod/category/list"}`,
method: "get",
});
}
// 新增优惠券
export function addCoupon(data) {
return request({
url: `${Market_BaseUrl + "/admin/coupon"}`,
method: data.id ? 'put' : 'post',
data
});
}
// 优惠券分页
export function couponPage(params) {
return request({
url: `${Market_BaseUrl + "/admin/coupon/page"}`,
method: "GET",
params
});
}
// 删除优惠券
export function delCoupon(params) {
return request({
url: `${Market_BaseUrl + "/admin/coupon"}`,
method: 'DELETE',
params
});
}
// 新增消费赠券
export function addConsumerCoupon(data) {
return request({
url: `${Market_BaseUrl + "/admin/consumerCoupon/addConsumerCoupon"}`,
method: 'post',
data
});
}
// 消费赠券分页
export function getConsumerCouponPage(params) {
return request({
url: `${Market_BaseUrl + "/admin/consumerCoupon/getConsumerCouponPage"}`,
method: "GET",
params
});
}
// 更新消费赠券
export function updateConsumerCouponById(data) {
return request({
url: `${Market_BaseUrl + "/admin/consumerCoupon/updateConsumerCouponById"}`,
method: 'put',
data
});
}
// 删除消费赠券
export function deleteConsumerCoupon(params) {
return request({
url: `${Market_BaseUrl + "/admin/consumerCoupon/deleteConsumerCoupon"}`,
method: 'DELETE',
params
});
}
// 获取该券关联的功能列表
export function relevanceCoupon(params) {
return request({
url: `${Market_BaseUrl + "/admin/coupon/gifts"}`,
method: 'get',
params
});
}
// 通过关联Id取消该券的关联
export function delRelevanceCoupon(params) {
return request({
url: `${Market_BaseUrl + "/admin/coupon/cancelGift"}`,
method: 'DELETE',
params
});
}
// 优惠券列表/已领取详情
export function couponRecord(params) {
return request({
url: `${Market_BaseUrl + "/admin/coupon/record"}`,
method: 'get',
params
});
}
// 删除用户优惠券
export function deleteRecord(params) {
return request({
url: `${Market_BaseUrl + "/admin/coupon/deleteRecord"}`,
method: 'DELETE',
params
});
}

View File

@@ -1,23 +0,0 @@
import request from "@/utils/request";
import { Market_BaseUrl } from "@/api/config";
import { get } from "lodash";
const baseURL = Market_BaseUrl + "/admin/coupon";
const API = {
getList(params: any) {
return request<any>({
url: `${baseURL}/page`,
method: "get",
params
});
},
//优惠券列表/已领取详情
getDetail(params: any) {
return request<any>({
url: `${baseURL}/record`,
method: "get",
params
});
},
}
export default API;

View File

@@ -1,240 +0,0 @@
import request from "@/utils/request";
import { Market_BaseUrl } from "@/api/config";
const baseURL = Market_BaseUrl + "/admin/member";
const API = {
getConfig(params: any) {
return request<any>({
url: `${baseURL}`,
method: "get",
params
});
},
editConfig(data: editRequest) {
return request({
url: `${baseURL}`,
method: "post",
data: data,
});
},
levelAdd(data: levelAddRequest) {
return request({
url: `${baseURL}/level`,
method: "post",
data: data,
});
},
levelEdit(data: levelEditRequest) {
return request({
url: `${baseURL}/level`,
method: "put",
data: data,
});
},
levelDel(data: levelDelRequest) {
return request<any>({
url: `${baseURL}/level/${data.id}`,
method: "delete",
// data
});
},
levelList(params: any) {
return request<any>({
url: `${baseURL}/level/list`,
method: "get",
params
});
},
}
export default API;
/**
* MemberConfigDTO
*/
export interface editRequest {
/**
* 条件开通条件项
*/
conditionList?: Condition[] | null;
/**
* 金额购买方案列表
*/
configList?: ConfigList[] | null;
/**
* 每消费一元经验值
*/
costReward?: number | null;
/**
* id
*/
id: number | null;
/**
* 是否享受会员价
*/
isMemberPrice: number | null;
/**
* 是否开启
*/
isOpen: string;
/**
* 提交生日/姓名
*/
isSubmitInfo: number | null;
/**
* 参与会员价门店
*/
memberPriceShopIdList?: number[] | null;
/**
* 每充值一元经验值
*/
rechargeReward?: number | null;
/**
* 规则说明
*/
remark: null | string;
[property: string]: any;
}
/**
* com.czg.account.dto.MemberConfigDTO.condition
*
* condition
*/
export interface Condition {
code?: null | string;
value?: null | string;
[property: string]: any;
}
/**
* com.czg.account.dto.MemberConfigDTO.ConfigList
*
* ConfigList
*/
export interface ConfigList {
/**
* 会员周期 1月 1日
*/
circleTime: null | string;
/**
* 赠送优惠券
*/
couponIdList?: number[] | null;
/**
* 名称
*/
name: null | string;
/**
* 价格
*/
price: number | null;
/**
* 赠送成长值
*/
reward?: number | null;
[property: string]: any;
}
/**
* MemberLevelDTO
*/
export interface levelAddRequest {
/**
* 消费送积分消费n元送1积分, 0为禁用
*/
costRewardPoints?: number | null;
/**
* 优惠券列表
*/
cycleRewardCouponList?: number[] | null;
/**
* 赠送积分
*/
cycleRewardPoints?: number | null;
/**
* 周期时间包含周 月 年 日
*/
cycleTime?: null | string;
/**
* 会员折扣
*/
discount: number | null;
/**
* 所需成长值
*/
experienceValue: number | null;
/**
* ID
*/
id?: number | null;
/**
* 周期奖励状态 0禁用 1启用
*/
isCycleReward: number | null;
/**
* logo
*/
logo?: null | string;
/**
* 会员名称
*/
name: null | string;
/**
* 描述说明
*/
remark: string;
[property: string]: any;
}
/**
* MemberLevelDTOUpdateGroup
*/
export interface levelEditRequest {
/**
* 消费送积分消费n元送1积分, 0为禁用
*/
costRewardPoints?: number | null;
/**
* 优惠券列表
*/
cycleRewardCouponList?: number[] | null;
/**
* 赠送积分
*/
cycleRewardPoints?: number | null;
/**
* 周期时间包含周 月 年 日
*/
cycleTime?: null | string;
/**
* 会员折扣
*/
discount?: number | null;
/**
* 所需成长值
*/
experienceValue?: number | null;
/**
* ID
*/
id: number | null;
/**
* 周期奖励状态 0禁用 1启用
*/
isCycleReward?: number | null;
/**
* logo
*/
logo?: null | string;
/**
* 会员名称
*/
name?: null | string;
[property: string]: any;
}
export interface levelDelRequest {
id: number;
[property: string]: any;
}

View File

@@ -1,58 +0,0 @@
import request from "@/utils/request";
import { Account_BaseUrl } from "@/api/config";
const baseURL = Account_BaseUrl + "/admin";
// 供应商
const Api = {
/** 通知消息列表*/
getList(params: any) {
return request<any>({
url: `${baseURL}/syncNotice`,
method: "get",
params,
});
},
/** 全部*/
getAllList(params: any) {
return request<any>({
url: `${baseURL}/list`,
method: "get",
params,
});
},
get(id: string | number) {
return request<any>({
url: `${baseURL}/` + id,
method: "get",
});
},
add(data: any) {
return request<any>({
url: `${baseURL}`,
method: "post",
data,
});
},
edit(data: any) {
return request<any>({
url: `${baseURL}/syncNotice/read`,
method: "put",
data,
});
},
delete(id: string | number) {
return request<any>({
url: `${baseURL}/syncNotice?id=` + id,
method: "delete",
});
},
// 清空已读
syncNoticeclear() {
return request<any>({
url: `${baseURL}/syncNotice/clear`,
method: "delete",
});
},
};
export default Api;

View File

@@ -55,7 +55,7 @@ const AuthAPI = {
method: "delete",
});
},
// 同步
// 退款退回
refundToStock(data: any) {
return request<any, Responseres>({
url: `${baseURL}/refundToStock`,
@@ -63,14 +63,6 @@ const AuthAPI = {
data,
});
},
// 退款退回
sync(data: any) {
return request<any, Responseres>({
url: `${baseURL}/sync`,
method: "post",
data,
});
},
// 耗材列表
productcons(params: any) {

View File

@@ -1,51 +0,0 @@
import request from "@/utils/request";
import { Product_BaseUrl } from "@/api/config";
const baseURL = Product_BaseUrl + "/admin/product";
// 供应商
const Api = {
/** 耗材库存变动记录*/
getList(params: any) {
return request<any>({
url: `${baseURL}/stock/flow`,
method: "get",
params,
});
},
/** 全部*/
getAllList(params: any) {
return request<any>({
url: `${baseURL}/list`,
method: "get",
params,
});
},
get(id: string | number) {
return request<any>({
url: `${baseURL}/` + id,
method: "get",
});
},
add(data: any) {
return request<any>({
url: `${baseURL}`,
method: "post",
data,
});
},
edit(data: any) {
return request<any>({
url: `${baseURL}`,
method: "put",
data,
});
},
delete(id: string | number) {
return request<any>({
url: `${baseURL}/` + id,
method: "delete",
});
},
};
export default Api;

View File

@@ -8,7 +8,7 @@ const Api = {
return request<any>({
url: `${baseURL}/in`,
method: "post",
data,
data
});
},
//出库
@@ -16,7 +16,7 @@ const Api = {
return request<any>({
url: `${baseURL}/out`,
method: "post",
data,
data
});
},
// 库存盘点记录
@@ -24,7 +24,7 @@ const Api = {
return request<any>({
url: `${baseURL}/checkRecord`,
method: "get",
params,
params
});
},
//库存盘点
@@ -32,7 +32,7 @@ const Api = {
return request<any>({
url: `${baseURL}/check`,
method: "post",
data,
data
});
},
//耗材报损
@@ -41,7 +41,7 @@ const Api = {
return request<any>({
url: `${baseURL}/reportDamage`,
method: "post",
data,
data
});
},
//耗材库存变动记录
@@ -49,17 +49,11 @@ const Api = {
return request<any>({
url: `${baseURL}/flow`,
method: "get",
params,
});
},
//耗材库存变动记录
reportinglosses(data: any) {
return request<any>({
url: `${baseURL}/reportDamage`,
method: "POST",
data,
params
});
},
};
export default Api;

View File

@@ -1,60 +0,0 @@
import request from "@/utils/request";
const baseURL = "/product/admin/product/vendor";
// 供应商账单
const AuthAPI = {
/** 供应商账单统计*/
getSummary(params: any) {
return request<any, Responseres>({
url: `${baseURL}/summary`,
method: "get",
params,
});
},
/** 分页*/
getPage(params: any) {
return request<any, Responseres>({
url: `${baseURL}/bill`,
method: "get",
params,
});
},
// 账单记录
getRecordList(params: any) {
return request<any, Responseres>({
url: `${baseURL}/bill/record`,
method: "get",
params,
});
},
// 账单付款记录
getPayRecordList(params: any) {
return request<any, Responseres>({
url: `${baseURL}/bill/pay/record`,
method: "get",
params,
});
},
// 账单付款
billPay(data: any) {
return request<any, Responseres>({
url: `${baseURL}/bill/pay`,
method: "post",
data,
});
},
};
export interface Responseres {
code?: number | null;
data?: any;
msg?: null | string;
[property: string]: any;
}
export default AuthAPI;

View File

@@ -246,7 +246,6 @@ export interface UserInfo {
* 用户分页查询对象
*/
export interface UserPageQuery extends PageQuery {
times: any;
/** 搜索关键字 */
keywords?: string;

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 900 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 957 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 805 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 943 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 895 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 947 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 945 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 813 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1018 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 857 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 962 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 930 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 930 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 792 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 777 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 857 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 896 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 857 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 774 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 935 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 918 B

View File

@@ -10,6 +10,8 @@ defineOptions({
inheritAttrs: false,
});
import { isExternal } from "@/utils/index";
const props = defineProps({

View File

@@ -1,10 +1,7 @@
<template>
<el-breadcrumb class="flex-y-center">
<el-breadcrumb-item v-for="(item, index) in breadcrumbs" :key="item.path">
<span
v-if="item.redirect === 'noredirect' || index === breadcrumbs.length - 1"
class="color-gray-400"
>
<span v-if="item.redirect === 'noredirect' || index === breadcrumbs.length - 1" class="color-gray-400">
{{ translateRouteTitle(item.meta.title) }}
</span>
<a v-else @click.prevent="handleLink(item)">

View File

@@ -515,7 +515,6 @@ import {
import ExcelJS from "exceljs";
import { reactive, ref } from "vue";
import type { IContentConfig, IObject, IOperatData } from "./types";
import { el } from "element-plus/es/locale";
// 定义接收的属性
const props = defineProps<{
@@ -593,45 +592,6 @@ const selectionData = ref<IObject[]>([]);
// 删除ID集合 用于批量删除
const removeIds = ref<(number | string)[]>([]);
function handleSelectionChange(selection: any[]) {
console.log("selectionData.value", selectionData.value);
// if(selection.length==0){
// selectionData.value=selectionData.value.filter((item) => {
// return pageData.value.find(v=>v[pk]===item[pk])!=undefined
// });
// }else{
// selectionData.value=selectionData.value.filter((item) => {
// return pageData.value.find(v=>v[pk]===item[pk])==undefined
// });
// }
//之前有选中,现在置空
if (selection.length == 0 && selectionData.value.length > 0) {
defaultSelData.value = defaultSelData.value.filter((item) => {
return pageData.value.find((v) => v[pk] === item[pk]) != undefined;
});
}
//之前没有选中,现在有
if (selection.length > 0 && selectionData.value.length == 0) {
defaultSelData.value = selection;
}
//之前有选中,现在有
if (selection.length > 0 && selectionData.value.length > 0) {
defaultSelData.value = defaultSelData.value.filter((item) => {
const isNowPageData = pageData.value.find((v) => v[pk] === item[pk]);
if (isNowPageData) {
return selection.find((v) => v[pk] === item[pk]) != undefined;
} else {
return true;
}
});
for (let i of selection) {
if (defaultSelData.value.find((v) => v[pk] === i[pk]) == undefined) {
defaultSelData.value.push(i);
}
}
}
console.log("defaultSelData.value", defaultSelData.value);
selectionData.value = selection;
removeIds.value = selection.map((item) => item[pk]);
}
@@ -1030,9 +990,6 @@ function fetchPageData(formData: IObject = {}, isRestart = false) {
} else {
pageData.value = data;
}
nextTick(() => {
setSelectTable(defaultSelData.value);
});
})
.finally(() => {
loading.value = false;
@@ -1073,42 +1030,14 @@ function saveXlsx(fileData: BlobPart, fileName: string) {
document.body.removeChild(downloadLink);
window.URL.revokeObjectURL(downloadUrl);
}
function test(rows: any[]) {}
const defaultSelData = ref<IObject[]>([]);
// 设置默认选择
function setSelectTable(rows: any[]) {
selectionData.value = rows;
defaultSelData.value = rows;
pageData.value.forEach((element: IObject) => {
rows.forEach((row) => {
if (element.id == row.id) {
console.log("selected", element);
tableRef.value!.toggleRowSelection(element, true);
}
});
});
function test(rows: any[]) {
console.log(tableRef, "tioshi222222222222222222222");
// rows.forEach((row) => {
// tableRef.value!.toggleRowSelection(row, undefined)
// })
}
//清除选中
function clearSelectTable() {
selectionData.value = [];
defaultSelData.value = [];
pageData.value.forEach((element: IObject) => {
tableRef.value!.toggleRowSelection(element, false);
});
}
// 暴露的属性和方法
defineExpose({
clearSelectTable,
fetchPageData,
exportPageData,
getFilterParams,
getselectTable,
pagination,
test,
setSelectTable,
});
defineExpose({ fetchPageData, exportPageData, getFilterParams, getselectTable, pagination, test });
</script>
<style lang="scss" scoped>

View File

@@ -1,44 +1,45 @@
<template>
<el-dialog v-model="dialogVisible" :title="props.title" :width="props.width" @close="close">
<el-dialog v-model="dialogVisible" :title="props.title" :width="props.width">
<slot></slot>
<template #footer>
<span class="dialog-footer">
<el-button @click="close">取消</el-button>
<el-button type="primary" @click="Confirm">确定</el-button>
<el-button @click="dialogVisible = false">取消</el-button>
<el-button type="primary" @click="Confirm">
确定
</el-button>
</span>
</template>
</el-dialog>
</template>
<script lang="ts" setup>
import { ref } from "vue";
import { ElMessageBox } from "element-plus";
import { ref } from 'vue'
import { ElMessageBox } from 'element-plus'
let props = defineProps({
title: {
type: String,
default: "Dialog",
default: 'Dialog'
},
width: {
type: String,
default: "30%",
},
});
const emit = defineEmits(["confirm", "close"]);
const dialogVisible = ref(false);
default: '30%'
}
})
const emit = defineEmits(['confirm'])
const dialogVisible = ref(false)
function open() {
dialogVisible.value = true;
dialogVisible.value = true
}
function Confirm() {
emit("confirm");
emit('confirm')
}
function close() {
dialogVisible.value = false;
emit("close");
dialogVisible.value = false
}
defineExpose({ open, close });
defineExpose({ open, close })
</script>
<style scoped>
.dialog-footer button:first-child {

View File

@@ -1,98 +0,0 @@
//收银机菜单列表
export const casher_windows_menus = [
{
title: '销售汇总',
icon: '/static/indexImg/PAGE_SALES_SUMMARY.svg',
pageUrl: 'PAGES_SALES_SUMMARY'
},
{
title: '代客下单',
icon: '/static/indexImg/icon-substitute-ordering.svg',
pageUrl: 'PAGES_CREATE_ORDER',
},
{
title: '桌台',
icon: '/static/indexImg/icon-table.svg',
pageUrl: 'PAGES_TABLE'
},
{
title: '商品管理',
icon: '/static/indexImg/icon-product-control.svg',
pageUrl: 'PAGES_PRODUCT'
},
{
title: '分组管理',
icon: '/static/indexImg/goods-group.svg',
pageUrl: 'PAGES_GOODS_GROUP'
},
{
title: '分类管理',
icon: '/static/indexImg/icon-category.svg',
pageUrl: 'PAGES_CATEGORY'
},
{
title: '会员管理',
icon: '/static/indexImg/icon-user.svg',
pageUrl: 'PAGES_USER_CONTROL'
},
{
title: '员工管理',
icon: '/static/indexImg/icon-staff.svg',
pageUrl: 'PAGES_STAFF'
},
{
title: '耗材管理',
icon: '/static/indexImg/PAGE_SALES_SUMMARY.svg',
pageUrl: 'PAGES_SALES_CONSUMABLES'
},
{
title: '订单管理',
icon: '/static/indexImg/icon-order.svg',
pageUrl: 'PAGES_ORDER_INDEX'
},
{
title: '设备管理',
icon: '/static/indexImg/icon-printer.svg',
pageUrl: 'PAGES_PRINTER_INDEX'
},
{
title: '交班',
icon: '/static/indexImg/icon-work.svg',
pageUrl: 'PAGES_WORK_INDEX'
},
{
title: '排队',
icon: '/static/indexImg/icon-line-up.svg',
pageUrl: 'PAGES_LINE_UP'
},
{
title: '霸王餐',
icon: '/static/indexImg/icon-bwc.svg',
pageUrl: 'PAGES_BWC'
},
{
title: '优惠券',
icon: '/static/coupon/icon_coupon.svg',
pageUrl: 'PAGES_COUPON_INDEX'
},
{
title: '订阅通知',
icon: '/static/indexImg/icon-notification.svg',
pageUrl: 'PAGES_NOTIFICATION_INDEX'
},
{
title: '挂账管理',
icon: '/static/indexImg/icon_credit.svg',
pageUrl: 'PAGES_CREDIT_BUYER_INDEX'
},
{
title: '核销管理',
icon: '/static/indexImg/pagewriteoff.svg',
pageUrl: 'PAGES_WEITEOFF'
},
{
title: '退出登录',
icon: '/static/indexImg/icon-login-out.svg',
pageUrl: 'PAGES_LOGIN',
}
]

View File

@@ -1,70 +1,19 @@
<template>
<div class="logo wh-full flex-center">
<!-- <transition name="el-fade-in-linear" mode="out-in"> -->
<!-- <router-link :key="+collapse" class="wh-full flex-center" to="/"> -->
<img :src="state.userInfo.logo" class="w20px h20px" />
<!-- <span v-if="!collapse" class="title">{{ userStore.userInfo.shopName }}</span> -->
<el-dropdown trigger="click" @command="handleCommand">
<div class="el-dropdown-link" style="display: flex;">
<div v-if="!collapse" class="title">{{ state.shopName }}</div>
<el-icon class="el-icon--right" v-if="loginType == 0">
<arrow-down />
</el-icon>
</div>
<template #dropdown>
<el-dropdown-menu v-if="loginType == 0">
<el-dropdown-item :command="item.shopId" v-for="(item, index) in state.branchList" :key="index"> {{
item.shopName }}</el-dropdown-item>
</el-dropdown-menu>
</template>
</el-dropdown>
<!-- </router-link> -->
<!-- </transition> -->
<div class="logo">
<transition name="el-fade-in-linear" mode="out-in">
<router-link :key="+collapse" class="wh-full flex-center" to="/">
<img :src="userStore.userInfo.logo" class="w20px h20px" />
<span v-if="!collapse" class="title">{{ userStore.userInfo.shopName }}</span>
</router-link>
</transition>
</div>
</template>
<script setup>
<script lang="ts" setup>
import defaultSettings from "@/settings";
import { useUserStore } from "@/store";
import ShopApi from "@/api/account/shop";
const userStore = useUserStore();
const state = reactive({
branchList: [],
userInfo: useUserStore().userInfo,
shopName: useUserStore().userInfo.shopName
});
const loginType = ref(localStorage.getItem("loginType"))
onMounted(() => {
geiShopList()
});
async function geiShopList() {
let res = await ShopApi.getBranchList()
state.branchList = res;
if (!localStorage.getItem("shopName")) {
state.shopName = state.branchList[0].shopName
localStorage.setItem("branch_shopId", state.branchList[0].id)
localStorage.setItem("shopName", state.branchList[0].shopName)
} else {
state.shopName = localStorage.getItem("shopName")
}
}
async function handleCommand(command) {
console.log(command)
let res = state.branchList.filter(v => v.shopId == command)[0]
// localStorage.getItem("shopId")
if (localStorage.getItem("shopId") == command) {
return
}
await ShopApi.getBranchChange(res.shopId)
// localStorage.setItem("branch_shopId", res.shopId)
localStorage.setItem("shopName", res.shopName)
state.shopName = res.shopName
location.reload()
console.log(res)
console.log(command)
}
defineProps({
collapse: {
@@ -79,18 +28,16 @@ defineProps({
width: 100%;
height: $navbar-height;
background-color: $sidebar-logo-background;
cursor: pointer;
.title {
flex-shrink: 0;
/* 防止容器在空间不足时缩小 */
flex-shrink: 0; /* 防止容器在空间不足时缩小 */
margin-left: 10px;
font-size: 16px;
color: #5a5e66;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
max-width: 100px;
max-width: 150px;
}
}

View File

@@ -29,31 +29,13 @@
</el-menu-item>
</AppLink>
</template>
<template v-else-if="item.children && hasOneShowingChild(item.children, item)">
<AppLink
v-if="onlyOneChild.meta"
:to="{
path: resolvePath(onlyOneChild.path),
query: onlyOneChild.meta.params,
}"
>
<el-menu-item
:index="resolvePath(onlyOneChild.path)"
:class="{ 'one-menu submenu-title-noDropdown': !isNest }"
>
<SidebarMenuItemTitle
:icon="onlyOneChild.meta.icon || item.meta?.icon"
:title="onlyOneChild.meta.title"
/>
</el-menu-item>
</AppLink>
</template>
<!--【非叶子节点】显示含多个子节点的父菜单,或始终显示的单子节点 -->
<el-sub-menu v-else :index="resolvePath(item.path)" teleported>
<template #title>
<SidebarMenuItemTitle v-if="item.meta" :icon="item.meta.icon" :title="item.meta.title" />
</template>
<SidebarMenuItem
v-for="child in item.children"
:key="child.path"
@@ -113,10 +95,6 @@ const onlyOneChild = ref();
* @returns 是否仅有一个可见子节点
*/
function hasOneShowingChild(children: RouteRecordRaw[] = [], parent: RouteRecordRaw) {
if (parent.name == "marketing_center") {
console.log(children);
console.log(parent);
}
// 过滤出可见子节点
const showingChildren = children.filter((route: RouteRecordRaw) => {
if (!route.meta?.hidden) {
@@ -223,7 +201,4 @@ function resolvePath(routePath: string) {
.el-menu-item {
color: rgb(153, 153, 153);
}
.one-menu {
color: #555;
}
</style>

View File

@@ -29,7 +29,6 @@ import NavbarRight from "../NavBar/components/NavbarRight.vue";
const appStore = useAppStore();
const settingsStore = useSettingsStore();
const permissionStore = usePermissionStore();
console.log(permissionStore.routes);
const sidebarLogo = computed(() => settingsStore.sidebarLogo);
const layout = computed(() => settingsStore.layout);

View File

@@ -1,5 +1,5 @@
import type { App } from "vue";
import { createRouter, createWebHashHistory, createWebHistory, type RouteRecordRaw } from "vue-router";
import { createRouter, createWebHashHistory, type RouteRecordRaw } from "vue-router";
export const Layout = () => import("@/layout/index.vue");
@@ -63,6 +63,38 @@ export const constantRoutes: RouteRecordRaw[] = [
keepAlive: true,
},
},
{
path: "credit",
name: "",
component: () => import("@/views/data/credit/index.vue"),
meta: {
title: "挂账管理",
affix: false,
keepAlive: true,
},
},
{
path: "credit-detail",
name: "",
component: () => import("@/views/data/credit/detail.vue"),
meta: {
title: "挂账明细",
affix: false,
keepAlive: true,
hidden: true
},
},
{
path: "work",
name: "",
component: () => import("@/views/data/work.vue"),
meta: {
title: "交班记录",
affix: false,
keepAlive: true,
},
},
{
path: "401",
component: () => import("@/views/error/401.vue"),
@@ -441,6 +473,7 @@ export const constantRoutes: RouteRecordRaw[] = [
// /**列表end */
// ],
// },
// {
@@ -676,7 +709,7 @@ export const constantRoutes: RouteRecordRaw[] = [
* 创建路由
*/
const router = createRouter({
history: createWebHistory(),
history: createWebHashHistory(),
routes: constantRoutes,
// 刷新时,滚动条位置还原
scrollBehavior: () => ({ left: 0, top: 0 }),

View File

@@ -22,11 +22,6 @@ export const useCartsStore = defineStore("carts", () => {
let dinnerType = ref<string>('dine-in');
//就餐模式 先付 后付
const isPayBefore = computed(() => {
return shopUser.userInfo.registerType == 'before' ? true : false;
});
//是否启用会员价
const useVipPrice = computed(() => {
@@ -781,7 +776,7 @@ export const useCartsStore = defineStore("carts", () => {
changeTable,
rotTable,
getGoods,
setGoodsMap, isPayBefore
setGoodsMap
};
});

View File

@@ -33,23 +33,6 @@ export const usePermissionStore = defineStore("permission", () => {
.then((data) => {
if (!isTest) {
const dynamicRoutes = parseDynamicRoutes(data.filter(v => v.type == 0));
console.log('dynamicRoutes')
console.log(dynamicRoutes)
dynamicRoutes.forEach((route) => {
//过滤出可见子节点
let onlyOneChild = null
const showingChildren = route.children.filter((route) => {
if (!route.meta?.hidden) {
onlyOneChild = route;
return true;
}
return false;
});
// 仅有一个节点
if (showingChildren.length === 1 && onlyOneChild) {
route.redirect = onlyOneChild.path;
}
})
routes.value = [...constantRoutes, ...dynamicRoutes];
isRoutesLoaded.value = true;
resolve(dynamicRoutes);

View File

@@ -31,14 +31,13 @@ export const useUserStore = defineStore("user", () => {
return new Promise<void>((resolve, reject) => {
AuthAPI.login(loginRequest)
.then((data) => {
isShopAdmin.value = data.loginType == 0 ? true : false;
Object.assign(userInfo.value, { ...data.shopInfo, shopId: data.shopInfo.id });
promissionList.value = data.promissionList;
const token = data.tokenInfo.tokenValue;
setToken(token);
setRefreshToken(token);
localStorage.setItem("shopId", "" + data.shopInfo.id);
localStorage.setItem("branch_shopId", data.shopInfo.id)
resolve();
})
.catch((error) => {
@@ -52,18 +51,16 @@ export const useUserStore = defineStore("user", () => {
*
* @returns {UserInfo} 用户信息
*/
function getUserInfo(shopId?: string | number) {
function getUserInfo() {
return new Promise<UserInfo>((resolve, reject) => {
ShopApi.get({ id: shopId || userInfo.value.shopId })
ShopApi.get({ id: userInfo.value.shopId })
.then((data) => {
if (!data) {
reject("Verification failed, please Login again.");
return;
}
console.log(userInfo)
console.log(data)
localStorage.setItem("shopId", "" + data.id);
Object.assign(userInfo.value, { ...data, roles: [], promissionList: [], shopId: data.id });
localStorage.setItem("shopId", "" + userInfo.value.shopId);
Object.assign(userInfo.value, { ...data, roles: [], promissionList: [], shopId: userInfo.value.shopId });
resolve(userInfo.value);
})
.catch((error) => {

View File

@@ -116,29 +116,4 @@ export function downloadFile(obj: BlobPart, name: string, suffix: string, useUni
document.body.appendChild(link);
link.click();
document.body.removeChild(link);
}
/**
* 判断主店同步是否启用
*/
export function isSyncStatus() {
let userInfo = ref(JSON.parse(localStorage.getItem('userInfo') || '{}'))
if (userInfo.value.isHeadShop == 0 && userInfo.value.isEnableProdSync == 1 && userInfo.value.isEnableVipSync == 1 && userInfo.value.isEnableConsSync == 1) {
return true
}else {
return false
}
}
/**
* 判断是否有某权限
*/
export function hasPermission(params: any) {
let $PermissionObj = JSON.parse(localStorage.getItem("permission") || '[]' )
const obj = $PermissionObj.find((v: any) => v == params || v == params)
if (obj) {
return obj
}
return false
}
}

View File

@@ -22,7 +22,6 @@ service.interceptors.request.use(
} else {
delete config.headers.token;
}
// config.headers.shopId = config.headers.shopId || localStorage.getItem("branch_shopId");
config.headers.shopId = config.headers.shopId || useUserStoreHook().userInfo.id;
return config;
},

View File

@@ -40,7 +40,7 @@
}"
@row-click="handleRowClick"
>
<el-table-column label="菜单名称" min-width="140">
<el-table-column label="菜单名称" min-width="100">
<template #default="scope">
{{ scope.row.title }}
</template>
@@ -162,7 +162,7 @@
<el-radio :value="2">接口</el-radio>
</el-radio-group>
</el-form-item>
<el-form-item label="是否外链" >
<el-form-item label="是否外链" prop="path">
<el-switch
v-model="formData.iFrame"
:active-value="1"
@@ -233,49 +233,6 @@
</el-input>
</el-form-item>
<el-form-item label="小程序路径" prop="miniPath">
<el-input v-model="formData.miniPath" placeholder="pages/index/index" />
</el-form-item>
<el-form-item label="小程序组件" prop="miniComponent">
<el-input v-model="formData.miniComponent" placeholder="小程序组件名称" />
</el-form-item>
<el-form-item label="小程序图标">
<single-image-upload
style="width: 100px; height: 100px"
v-model="formData.miniIcon"
></single-image-upload>
</el-form-item>
<el-form-item label="接口路径" prop="miniPage">
<div class="w-full">
<div>
<el-button @click="apiInfoPush" icon="plus" type="primary">添加</el-button>
</div>
<div class="u-flex u-m-t-10" v-for="(item, index) in formData.apiInfo" :key="index">
<el-form-item label="请求方式" label-position="left">
<el-select v-model="item.method" style="width: 100px">
<el-option
v-for="(item, index) in apiMethodOptions"
:key="index"
:value="item.value"
>
{{ item.label }}
</el-option>
</el-select>
</el-form-item>
<el-form-item label="接口地址" style="flex: 1">
<el-input v-model="item.url" placeholder="支持通配符*和?" />
</el-form-item>
<el-icon
style="margin-left: 10px"
size="20"
color="#F56c6c"
@click="formData.apiInfo.splice(index, 1)"
>
<RemoveFilled />
</el-icon>
</div>
</div>
</el-form-item>
<el-form-item v-if="formData.type !== MenuTypeEnum.BUTTON" prop="hidden" label="显示状态">
<el-radio-group v-model="formData.hidden">
<el-radio :value="1">隐藏</el-radio>
@@ -345,19 +302,7 @@ const dialog = reactive({
title: "新增菜单",
visible: false,
});
const apiMethodOptions = ref([
{ value: "All", label: "All" },
{ value: "GET", label: "GET" },
{ value: "POST", label: "POST" },
{ value: "PUT", label: "PUT" },
{ value: "DELETE", label: "DELETE" },
]);
function apiInfoPush() {
if (!formData.value.apiInfo) {
formData.value.apiInfo = [];
}
formData.value.apiInfo.push({ method: "All", url: "" });
}
// 查询参数
const queryParams = reactive<getListRequest>({});
// 菜单表格数据
@@ -381,10 +326,6 @@ const initialeditRequestData = ref<editRequest>({
path: "",
component: "",
name: "",
miniPath: "",
miniComponent: "",
miniIcon: "",
apiInfo: [],
});
// 菜单表单数据
const formData = ref({ ...initialeditRequestData.value });
@@ -473,7 +414,6 @@ function handleOpenDialog(pid?: string, menuId?: string) {
path: data.path || "", // Ensure path is always a string
title: data.title || "", // Ensure title is always a string
type: data.type ?? 0, // Ensure type is always a number
apiInfo: data.apiInfo ? JSON.parse(data.apiInfo) : [],
};
});
} else {

View File

@@ -28,8 +28,16 @@
</div>
</div>
<el-tree ref="permTreeRef" node-key="value" show-checkbox :data="menuPermOptions"
:filter-node-method="handlePermFilter" :default-expand-all="true" :check-strictly="!parentChildLinked" class="mt-5">
<el-tree
ref="permTreeRef"
node-key="value"
show-checkbox
:data="menuPermOptions"
:filter-node-method="handlePermFilter"
:default-expand-all="true"
:check-strictly="!parentChildLinked"
class="mt-5"
>
<template #default="{ data }">
{{ data.label }}
</template>
@@ -102,7 +110,7 @@ onMounted(() => {
watch(
() => modelValue.value,
(newval) => { }
(newval) => {}
);
function getPerms() {
@@ -114,6 +122,7 @@ function reset() {
}
function setChecked(checkedMenuIds) {
checkedMenuIds.forEach((menuId) => {
console.log(menuId);
permTreeRef.value.setChecked(menuId, true, false);
});
}
@@ -122,4 +131,4 @@ defineExpose({
setChecked,
reset,
});
</script>
</script>

View File

@@ -108,10 +108,10 @@
<el-form-item label="描述" prop="description">
<el-input type="textarea" v-model="formData.description" placeholder="描述" />
</el-form-item>
<el-alert title="角色菜单请点击角色列表的分配菜单按钮编辑" type="success" effect="dark" />
<!-- <el-form-item label="菜单分配" prop="menuIdList">
<el-form-item label="菜单分配" prop="menuIdList">
<menuSelect ref="refmenuSelect" v-model="formData.menuIdList"></menuSelect>
</el-form-item> -->
</el-form-item>
</el-form>
<template #footer>
@@ -123,90 +123,58 @@
</el-dialog>
<!-- 分配菜单弹窗 -->
<el-drawer v-model="assignPermDialogVisible" size="500">
<template #header>
<div>
<div>
<h3>
{{ "【" + checkedRole.name + "】菜单分配" }}
</h3>
</div>
<div>
<el-form-item label="平台类型">
<el-radio-group v-model="platformType" @change="handlePlatformTypeChange">
<el-radio :value="0">管理端</el-radio>
<el-radio :value="1">收银机</el-radio>
</el-radio-group>
</el-form-item>
</div>
<div class="flex-x-between">
<el-input v-model="permKeywords" clearable class="w-[150px]" placeholder="菜单菜单名称">
<template #prefix>
<Search />
</template>
</el-input>
<div class="flex-center ml-5">
<el-button type="primary" size="small" plain @click="togglePermTree">
<template #icon>
<Switch />
</template>
{{ isExpanded ? "收缩" : "展开" }}
</el-button>
<el-checkbox
v-model="parentChildLinked"
class="ml-5"
@change="handleparentChildLinkedChange"
>
父子联动
</el-checkbox>
<el-tooltip placement="bottom">
<template #content>
如果只需勾选菜单菜单不需要勾选子菜单或者按钮菜单请关闭父子联动
</template>
<el-icon class="ml-1 color-[--el-color-primary] inline-block cursor-pointer">
<QuestionFilled />
</el-icon>
</el-tooltip>
</div>
</div>
</div>
</template>
<div class="u-relative" style="overflow-x: hidden">
<el-tree
ref="permTreeRef"
node-key="value"
show-checkbox
:data="menuPermOptions"
:default-checked-keys="adminMenuIdList"
:filter-node-method="handlePermFilter"
:default-expand-all="true"
:check-strictly="!parentChildLinked"
class="mt-5"
>
<template #default="{ data }">
{{ data.label }}
<el-drawer
v-model="assignPermDialogVisible"
:title="'【' + checkedRole.name + '】菜单分配'"
size="500"
>
<div class="flex-x-between">
<el-input v-model="permKeywords" clearable class="w-[150px]" placeholder="菜单菜单名称">
<template #prefix>
<Search />
</template>
</el-tree>
<div
class="cashMenuIdList"
:style="{
transform: `translateX(${(platformType == 1 ? 0 : 1) * 100}%)`,
}"
>
<el-checkbox-group v-model="cashMenuIdList">
<el-checkbox
v-for="(item, index) in casher_windows_menus"
:key="index"
:value="item.menuId"
>
{{ item.name }}
</el-checkbox>
</el-checkbox-group>
</el-input>
<div class="flex-center ml-5">
<el-button type="primary" size="small" plain @click="togglePermTree">
<template #icon>
<Switch />
</template>
{{ isExpanded ? "收缩" : "展开" }}
</el-button>
<el-checkbox
v-model="parentChildLinked"
class="ml-5"
@change="handleparentChildLinkedChange"
>
父子联动
</el-checkbox>
<el-tooltip placement="bottom">
<template #content>
如果只需勾选菜单菜单不需要勾选子菜单或者按钮菜单请关闭父子联动
</template>
<el-icon class="ml-1 color-[--el-color-primary] inline-block cursor-pointer">
<QuestionFilled />
</el-icon>
</el-tooltip>
</div>
</div>
<el-tree
ref="permTreeRef"
node-key="value"
show-checkbox
:data="menuPermOptions"
:filter-node-method="handlePermFilter"
:default-expand-all="true"
:check-strictly="!parentChildLinked"
class="mt-5"
>
<template #default="{ data }">
{{ data.label }}
</template>
</el-tree>
<template #footer>
<div class="dialog-footer">
<el-button type="primary" @click="handleAssignPermSubmit"> </el-button>
@@ -223,11 +191,11 @@ defineOptions({
inheritAttrs: false,
});
import { useUserStore } from "@/store/modules/user";
// import { casher_windows_menus } from "@/data/menus";
const shopUser = useUserStore();
import menuSelect from "./components/menus.vue";
import RoleApi, { SysRole, addRequest, getListRequest } from "@/api/account/role";
import MenuAPI, { type RouteVO, CashMenu } from "@/api/account/menu";
import MenuAPI, { type RouteVO } from "@/api/account/menu";
const queryFormRef = ref();
const addRequestRef = ref();
@@ -253,7 +221,6 @@ const menuPermOptions = ref<RouteVO[]>([]);
const dialog = reactive({
title: "",
visible: false,
row: {},
});
// 角色表单
const formData = reactive<addRequest>({
@@ -265,7 +232,7 @@ const formData = reactive<addRequest>({
menuIdList: [],
description: "",
});
const cashMenuIdList = ref<number[]>([]);
const rules = reactive({
name: [{ required: true, message: "请输入角色名称", trigger: "blur" }],
level: [{ required: false, message: "请输入角色等级", trigger: "blur" }],
@@ -284,14 +251,6 @@ const isExpanded = ref(true);
const parentChildLinked = ref(false);
const platformType = ref(0);
function handlePlatformTypeChange(e: string | number | boolean | undefined) {
const value = Number(e); // Ensure the value is cast to a number
console.log("handlePlatformTypeChange");
platformType.value = value;
handleOpenAssignPermDialog(dialog.row);
}
// 查询
function handleQuery() {
loading.value = true;
@@ -322,16 +281,15 @@ function handleSelectionChange(selection: any) {
// 打开角色弹窗
async function handleOpenDialog(row: SysRole) {
dialog.visible = true;
dialog.row = row;
if (row && row.id) {
dialog.title = "修改角色";
//获取角色菜单列表
const data = await RoleApi.getMenu(row.id, platformType.value);
const data = await RoleApi.getMenu(row.id);
console.log(data);
Object.assign(formData, row);
formData.menuIdList = data;
setTimeout(() => {
// refmenuSelect.value.setChecked(data);
refmenuSelect.value.setChecked(data);
}, 300);
console.log(formData);
} else {
@@ -343,12 +301,11 @@ async function handleOpenDialog(row: SysRole) {
function handleSubmit() {
addRequestRef.value.validate((valid: any) => {
if (valid) {
// const checkedMenuIds: number[] = refmenuSelect.value.getPerms();
const checkedMenuIds: number[] = refmenuSelect.value.getPerms();
loading.value = true;
const roleId = formData.id;
if (roleId) {
// RoleApi.update(roleId, { ...formData, menuIdList: checkedMenuIds })
RoleApi.update(roleId, formData)
RoleApi.update(roleId, { ...formData, menuIdList: checkedMenuIds })
.then(() => {
ElMessage.success("修改成功");
handleCloseDialog();
@@ -372,9 +329,9 @@ function handleSubmit() {
// 关闭弹窗
function handleCloseDialog() {
addRequestRef.value?.resetFields();
addRequestRef.value?.clearValidate();
refmenuSelect.value?.reset();
addRequestRef.value.resetFields();
addRequestRef.value.clearValidate();
refmenuSelect.value.reset();
formData.id = undefined;
formData.sort = 1;
formData.status = 1;
@@ -426,13 +383,6 @@ function returnMenu(menu) {
});
}
const casher_windows_menus = ref<CashMenu[]>([]);
//获取收银机菜单
async function getCashMenus() {
const res = await MenuAPI.getCashMenus();
console.log(res);
casher_windows_menus.value = res;
}
// 获取所有的菜单
async function getMenuPermOptions() {
let arr =
@@ -440,42 +390,26 @@ async function getMenuPermOptions() {
menuPermOptions.value = returnMenu(arr);
}
getMenuPermOptions();
getCashMenus();
const adminMenuIdList = ref<number[]>([]);
// 打开分配菜单菜单弹窗
async function handleOpenAssignPermDialog(row: SysRole) {
const roleId = row.id;
dialog.row = row;
if (roleId) {
assignPermDialogVisible.value = true;
loading.value = true;
checkedRole.value.id = roleId;
checkedRole.value.name = row.name as string;
getMenuIds(roleId);
}
}
// 回显角色已拥有的菜单
function getMenuIds(roleId: number) {
roleId = roleId ? roleId : dialog.row.id;
if (!roleId) {
return;
}
RoleApi.getMenu(roleId, platformType.value)
.then((data) => {
if (platformType.value == 0) {
// 回显角色已拥有的菜单
RoleApi.getMenu(roleId)
.then((data) => {
const checkedMenuIds = data;
adminMenuIdList.value = data;
// checkedMenuIds.forEach((menuId) => permTreeRef.value!.setChecked(menuId, true, false));
}
if (platformType.value == 1) {
cashMenuIdList.value = data;
}
})
.finally(() => {
loading.value = false;
});
checkedMenuIds.forEach((menuId) => permTreeRef.value!.setChecked(menuId, true, false));
})
.finally(() => {
loading.value = false;
});
}
}
// 分配菜单菜单提交
@@ -488,13 +422,7 @@ function handleAssignPermSubmit() {
.map((node: any) => node.value);
loading.value = true;
RoleApi.update(roleId, {
name,
adminMenuIdList: checkedMenuIds,
cashMenuIdList: cashMenuIdList.value.filter((id) =>
casher_windows_menus.value.find((v) => v.menuId == id)
),
})
RoleApi.update(roleId, { name, menuIdList: checkedMenuIds })
.then(() => {
ElMessage.success("分配菜单成功");
assignPermDialogVisible.value = false;
@@ -542,9 +470,6 @@ watch(
(val) => {
if (!val) {
permTreeRef.value.setCheckedKeys([]);
platformType.value = 0;
cashMenuIdList.value = [];
adminMenuIdList.value = [];
}
}
);
@@ -568,14 +493,3 @@ onMounted(() => {
handleQuery();
});
</script>
<style scoped lang="scss">
.cashMenuIdList {
position: absolute;
box-sizing: border-box;
padding: var(--el-drawer-padding-primary);
inset: 0;
background-color: #fff;
z-index: 2;
transition: all 0.3s ease-in-out;
}
</style>

View File

@@ -81,7 +81,6 @@ import couponEnum from "./couponEnum";
import couponDetails from "./components/coupon_details.vue";
import couponAdd from "./components/add.vue";
import couponApi from "@/api/account/coupon";
import { hasPermission } from "@/utils/index";
export default {
// eslint-disable-next-line vue/no-unused-components
@@ -101,9 +100,6 @@ export default {
},
mounted() {
this.getTableData();
console.log(hasPermission('coupon:add'))
console.log(hasPermission('coupon:edit'))
// coupon:add shopStaff:add
},
methods: {
toAdd(data) {

View File

@@ -47,29 +47,23 @@
</div> -->
<div class="h_card_wrap">
<div class="status_wrap">
<div class="left" style="flex-shrink: 0">
<div class="left">
<div class="dot" />
<span>营业</span>
</div>
<div class="u-flex" style="flex-wrap: wrap">
<el-select v-if="isHeadShop == 1&&loginType == 0" v-model="shopId" placeholder="选择分店" style="width: 200px; margin-right: 10px;" @change="shopChange">
<el-option v-for="item in branchList" :key="item.shopId" :label="item.shopName" :value="item.shopId" />
</el-select>
<div class="time_wrap u-flex" style="flex-shrink: 0">
<el-radio-group v-model="timeValue" class="m-r-5" @change="timeChange">
<el-radio-button value="0">今天</el-radio-button>
<el-radio-button value="-1">昨天</el-radio-button>
<el-radio-button value="-7">最近7天</el-radio-button>
<el-radio-button value="-30">最近30天</el-radio-button>
<el-radio-button value="week">本周</el-radio-button>
<el-radio-button value="month">本月</el-radio-button>
<el-radio-button value="custom">自定义</el-radio-button>
</el-radio-group>
<div class="u-flex">
<el-date-picker v-if="timeValue == 'custom'" v-model="query.createdAt" type="daterange"
range-separator="" start-placeholder="开始日期" end-placeholder="结束日期" value-format="YYYY-MM-DD HH:mm:ss"
@change="summarytrade" />
</div>
<div class="time_wrap u-flex">
<el-radio-group v-model="timeValue" class="m-r-5" @change="timeChange">
<el-radio-button value="0">今天</el-radio-button>
<el-radio-button value="-1">昨天</el-radio-button>
<el-radio-button value="-7">最近7天</el-radio-button>
<el-radio-button value="-30">最近30天</el-radio-button>
<el-radio-button value="week">本周</el-radio-button>
<el-radio-button value="month">本月</el-radio-button>
<el-radio-button value="custom">自定义</el-radio-button>
</el-radio-group>
<div class="u-flex">
<el-date-picker v-if="timeValue == 'custom'" v-model="query.createdAt" type="daterange" range-separator="至"
start-placeholder="开始日期" end-placeholder="结束日期" value-format="YYYY-MM-DD " @change="summarytrade" />
</div>
</div>
</div>
@@ -142,16 +136,16 @@
<div class="line_gropress">
<div class="gropress l" :style="{
width: `${trade.saleAmount
? (trade.saleAmount / (trade.saleAmount * 1 + trade.refundAmount * 1)) *
100
: 0
? (trade.saleAmount / (trade.saleAmount * 1 + trade.refundAmount * 1)) *
100
: 0
}%`,
}" />
<div class="gropress r" :style="{
width: `${trade.refundAmount
? (trade.refundAmount / (trade.saleAmount * 1 + trade.refundAmount * 1)) *
100
: 0
? (trade.refundAmount / (trade.saleAmount * 1 + trade.refundAmount * 1)) *
100
: 0
}%`,
}" />
</div>
@@ -171,18 +165,18 @@
<div class="line_gropress">
<div class="gropress l" :style="{
width: `${trade.rechargeAmount
? (trade.rechargeAmount /
(trade.memberPayAmount + trade.rechargeRefundAmount * 1)) *
100
: 0
? (trade.rechargeAmount /
(trade.memberPayAmount + trade.rechargeRefundAmount * 1)) *
100
: 0
}%`,
}" />
<div class="gropress r" :style="{
width: `${trade.rechargeRefundAmount
? (trade.rechargeRefundAmount /
(trade.memberPayAmount + trade.rechargeRefundAmount * 1)) *
100
: 0
? (trade.rechargeRefundAmount /
(trade.memberPayAmount + trade.rechargeRefundAmount * 1)) *
100
: 0
}%`,
}" />
</div>
@@ -338,7 +332,6 @@
<script>
import dataSummaryApi from "@/api/order/data-summary";
import ShopApi from "@/api/account/shop";
import dayjs from "dayjs";
import * as echarts from "echarts";
import { debounce, formatDecimal } from "@/utils/tools";
@@ -390,8 +383,6 @@ export default {
saveAmount: null,
},
],
branchList: [],
shopId: null,
trade: {},
formatDecimal,
topData: "",
@@ -428,8 +419,6 @@ export default {
},
tradeVip: "",
tradeCount: "",
isHeadShop: JSON.parse(localStorage.getItem("userInfo")).isHeadShop,
loginType: localStorage.getItem("loginType")
};
},
computed: {
@@ -484,22 +473,9 @@ export default {
// }
}, 100);
window.addEventListener("resize", this.__resizeHandler);
this.geiShopList()
// this.initCardUserChart();
},
methods: {
/**
* 获取分店列表
*/
async geiShopList() {
let res = await ShopApi.getBranchList()
this.branchList = res;
},
shopChange(){
this.summarytrade();
this.lineChartTypeChange(this.lineChartType)
this.dateProduct()
},
// 切换时间
timeChange(e) {
const format = ["YYYY-MM-DD 00:00:00", "YYYY-MM-DD 23:59:59"];
@@ -549,9 +525,7 @@ export default {
break;
case "custom":
// 自定义
this.query.createdAt = [
dayjs().add(-30, "d").format(format[0]),
dayjs().format(format[1]),];
this.query.createdAt = [];
break;
default:
break;
@@ -564,13 +538,9 @@ export default {
async summarytrade() {
try {
this.tradeLoading = true;
if( this.query.createdAt[1] ){
this.query.createdAt.splice(1,1,this.query.createdAt[1].replace("00:00:00","23:59:59"))
}
const res = await dataSummaryApi.trade({
beginDate: this.query.createdAt[0],
endDate: this.query.createdAt[1],
shopId: this.shopId
});
this.trade = res;
this.tradeLoading = false;
@@ -894,7 +864,7 @@ export default {
async dateAmount() {
try {
this.saleLoading = true;
const res = await dataSummaryApi.dateAmount({ day: this.saleActive,shopId: this.shopId });
const res = await dataSummaryApi.dateAmount({ day: this.saleActive });
const data = res.total.map((item) => {
return {
orderAmount: item.orderAmount,
@@ -923,7 +893,6 @@ export default {
day: this.saleTableActive,
page: this.saleTablePage,
size: this.saleTableSize,
shopId: this.shopId
});
this.saleTable = res.records;
this.saleTableTotal = res.totalRow * 1;
@@ -939,7 +908,7 @@ export default {
async datePayType() {
try {
this.payChartLoading = true;
const res = await dataSummaryApi.datePayType({ day: this.saleActive,shopId: this.shopId });
const res = await dataSummaryApi.datePayType({ day: this.saleActive });
const data = res.countPayType.map((item) => {
return {
value: item.count,

View File

@@ -10,18 +10,16 @@
<el-form-item>
<el-input placeholder="商品名称" v-model="query.productName" />
</el-form-item>
<el-form-item v-if="isHeadShop == 1&&loginType == 0">
<el-select v-model="shopId" placeholder="选择分店" style="width: 200px; margin-right: 10px"
@change="getCategory">
<el-option v-for="item in branchList" :key="item.shopId" :label="item.shopName" :value="item.shopId" />
<el-form-item>
<el-select v-model="query.prodCategoryId" placeholder="商品分类" style="width: 140px">
<el-option
:label="item.name"
:value="item.id"
v-for="item in categorys"
:key="item.id"
></el-option>
</el-select>
</el-form-item>
<!-- <el-form-item>
<el-select v-model="query.prodCategoryId" placeholder="商品分类" style="width: 140px">
<el-option :label="item.name" :value="item.id" v-for="item in categorys" :key="item.id"></el-option>
</el-select>
</el-form-item> -->
</template>
<el-form-item>
<el-radio-group v-model="timeValue" @change="timeChange">
@@ -34,9 +32,16 @@
<el-radio-button value="month">本月</el-radio-button>
<el-radio-button value="custom">自定义</el-radio-button>
</el-radio-group>
<el-date-picker class="u-m-l-10" v-model="query.createdAt" type="daterange" range-separator="至"
start-placeholder="开始日期" end-placeholder="结束日期" value-format="YYYY-MM-DD HH:mm:ss"
v-if="timeValue == 'custom'"></el-date-picker>
<el-date-picker
class="u-m-l-10"
v-model="query.createdAt"
type="daterange"
range-separator=""
start-placeholder="开始日期"
end-placeholder="结束日期"
value-format="YYYY-MM-DD"
v-if="timeValue == 'custom'"
></el-date-picker>
</el-form-item>
<el-form-item>
<el-button type="primary" @click="getTableData">查询</el-button>
@@ -52,9 +57,7 @@
<div class="collect_wrap">
<div class="item">
<div class="icon_wrap" style="--bg-color: #c978ee">
<el-icon color="#fff">
<Coin />
</el-icon>
<el-icon color="#fff"><Coin /></el-icon>
</div>
<div class="info">
<div class="m">{{ payCount.totalAmount || 0 }}</div>
@@ -63,9 +66,7 @@
</div>
<div class="item">
<div class="icon_wrap" style="--bg-color: #c978ee">
<el-icon color="#fff">
<Coin />
</el-icon>
<el-icon color="#fff"><Coin /></el-icon>
</div>
<div class="info">
<div class="m">{{ payCount.refundAmount || 0 }}</div>
@@ -74,9 +75,7 @@
</div>
<div class="item">
<div class="icon_wrap" style="--bg-color: #c978ee">
<el-icon color="#fff">
<ShoppingCartFull />
</el-icon>
<el-icon color="#fff"><ShoppingCartFull /></el-icon>
</div>
<div class="info">
<div class="m">{{ payCount.saleCount || 0 }}</div>
@@ -85,9 +84,7 @@
</div>
<div class="item">
<div class="icon_wrap" style="--bg-color: #c978ee">
<el-icon color="#fff">
<ShoppingCart />
</el-icon>
<el-icon color="#fff"><ShoppingCart /></el-icon>
</div>
<div class="info">
<div class="m">{{ payCount.refundCount || 0 }}</div>
@@ -148,9 +145,14 @@
</el-table>
</div>
<div class="head-container">
<el-pagination :total="tableData.total" :current-page="tableData.page" :page-size="tableData.size"
@current-change="paginationChange" @size-change="sizeChange"
layout="total, sizes, prev, pager, next, jumper"></el-pagination>
<el-pagination
:total="tableData.total"
:current-page="tableData.page"
:page-size="tableData.size"
@current-change="paginationChange"
@size-change="sizeChange"
layout="total, sizes, prev, pager, next, jumper"
></el-pagination>
</div>
</div>
</template>
@@ -158,7 +160,6 @@
<script>
import saleSummaryApi from "@/api/order/sale-summary";
import categoryApi from "@/api/product/productclassification";
import ShopApi from "@/api/account/shop";
import dayjs from "dayjs";
import { downloadFile } from "@/utils/index";
@@ -184,11 +185,6 @@ export default {
downloadLoading: false,
payCount: "",
payCountTotal: 0,
branchList: [],
shopId: null,
isHeadShop: JSON.parse(localStorage.getItem("userInfo")).isHeadShop,
loginType: localStorage.getItem("loginType")
};
},
filters: {
@@ -200,16 +196,8 @@ export default {
this.resetQuery = { ...this.query };
this.getTableData();
this.getCategory();
this.geiShopList();
},
methods: {
/**
* 获取分店列表
*/
async geiShopList() {
let res = await ShopApi.getBranchList()
this.branchList = res;
},
totalfilter(item, d) {
let num = item + d;
return num.toFixed(2);
@@ -217,12 +205,10 @@ export default {
// 获取商品分类
async getCategory() {
try {
this.query.prodCategoryId = ""
const res = await categoryApi.getList({
page: 1,
size: 200,
orderBy: "name asc",
shopId: this.shopId
});
this.categorys = res;
} catch (error) {
@@ -232,15 +218,12 @@ export default {
// 获取订单汇总
async daycount() {
try {
if (this.query.createdAt[1]) {
this.query.createdAt.splice(1, 1, this.query.createdAt[1].replace("00:00:00", "23:59:59"))
}
const res = await saleSummaryApi.count({
beginDate: this.query.createdAt[0],
endDate: this.query.createdAt[1],
prodCategoryId: this.query.prodCategoryId,
productName: this.query.productName,
shopId: this.shopId,
type: this.orderType,
});
this.payCount = res;
@@ -252,15 +235,11 @@ export default {
async downloadHandle() {
try {
this.downloadLoading = true;
if (this.query.createdAt[1]) {
this.query.createdAt.splice(1, 1, this.query.createdAt[1].replace("00:00:00", "23:59:59"))
}
const file = await saleSummaryApi.export({
beginDate: this.query.createdAt[0],
endDate: this.query.createdAt[1],
prodCategoryId: this.query.prodCategoryId,
productName: this.query.productName,
shopId: this.shopId
});
downloadFile(file, "数据", "xlsx");
this.downloadLoading = false;
@@ -290,9 +269,6 @@ export default {
this.tableData.loading = true;
try {
this.daycount();
if (this.query.createdAt[1]) {
this.query.createdAt.splice(1, 1, this.query.createdAt[1].replace("00:00:00", "23:59:59"))
}
const res = await saleSummaryApi.page({
page: this.tableData.page,
size: this.tableData.size,
@@ -301,7 +277,6 @@ export default {
endDate: this.query.createdAt[1],
productName: this.query.productName,
prodCategoryId: this.query.prodCategoryId,
shopId: this.shopId
});
this.tableData.loading = false;
this.tableData.data = res.records;

View File

@@ -6,7 +6,7 @@
</el-tabs> -->
<div class="head-container">
<el-form :model="query" inline label-position="left">
<div class="u-flex gap-10" style="flex-wrap: wrap;">
<div class="u-flex gap-10">
<el-radio-group v-model="timeValue" @change="timeChange">
<el-radio-button value="">全部</el-radio-button>
<el-radio-button value="0">今天</el-radio-button>
@@ -18,14 +18,14 @@
<el-radio-button value="custom">自定义</el-radio-button>
</el-radio-group>
<div>
<el-date-picker v-model="query.createdAt" type="daterange" range-separator="至" start-placeholder="开始日期"
end-placeholder="结束日期" value-format="YYYY-MM-DD HH:mm:ss"></el-date-picker>
</div>
<div>
<el-select v-model="shopId" v-if="isHeadShop == 1&& loginType == 0" placeholder="选择分店"
style="width: 200px; margin-right: 10px">
<el-option v-for="item in branchList" :key="item.shopId" :label="item.shopName" :value="item.shopId" />
</el-select>
<el-date-picker
v-model="query.createdAt"
type="daterange"
range-separator=""
start-placeholder="开始日期"
end-placeholder="结束日期"
value-format="YYYY-MM-DD"
></el-date-picker>
</div>
<div>
<el-button type="primary" @click="getTableData">查询</el-button>
@@ -100,7 +100,6 @@
<script>
import tableSummaryApi from "@/api/order/table-summary";
import ShopApi from "@/api/account/shop";
import dayjs from "dayjs";
import { downloadFile } from "@/utils/index";
@@ -126,11 +125,6 @@ export default {
downloadLoading: false,
payCountList: "",
payCountTotal: 0,
shopId: null,
branchList: [],
isHeadShop: JSON.parse(localStorage.getItem("userInfo")).isHeadShop,
loginType: localStorage.getItem("loginType")
};
},
filters: {
@@ -141,16 +135,8 @@ export default {
mounted() {
this.resetQuery = { ...this.query };
this.getTableData();
this.geiShopList();
},
methods: {
/**
* 获取分店列表
*/
async geiShopList() {
let res = await ShopApi.getBranchList()
this.branchList = res;
},
//携带table id跳转到订单列表页面
toTableOrderList(data) {
// console.log(data)
@@ -166,13 +152,9 @@ export default {
async downloadHandle() {
try {
this.downloadLoading = true;
if (this.query.createdAt[1]) {
this.query.createdAt.splice(1, 1, this.query.createdAt[1].replace("00:00:00", "23:59:59"))
}
const file = await tableSummaryApi.export({
beginDate: this.query.createdAt[0],
endDate: this.query.createdAt[1],
shopId: this.shopId
});
downloadFile(file, "数据", "xlsx");
this.downloadLoading = false;
@@ -201,15 +183,11 @@ export default {
async getTableData() {
this.tableData.loading = true;
try {
if (this.query.createdAt[1]) {
this.query.createdAt.splice(1, 1, this.query.createdAt[1].replace("00:00:00", "23:59:59"))
}
const res = await tableSummaryApi.list({
page: this.tableData.page,
size: this.tableData.size,
beginDate: this.query.createdAt[0],
endDate: this.query.createdAt[1],
shopId: this.shopId
});
this.tableData.loading = false;
this.tableData.data = res;

View File

@@ -1,171 +0,0 @@
<template>
<div class="app-container">
<div class="head-container">
<el-card shadow="never">
<el-alert title="当前列表仅作为数据记录,不产生任何实际交易。" type="warning" show-icon :closable="false"
style="margin-bottom: 15px;" />
<el-row :gutter="20">
<el-col :span="4">
<el-input v-model="state.query.name" clearable placeholder="请输入耗材名称" style="width: 100%" class="filter-item"
@keyup.enter="getTableData" />
</el-col>
<el-col :span="16">
<el-button type="primary" @click="getTableData">查询</el-button>
<el-button type="primary" @click="handlePayment('all')" plain>批量付款</el-button>
<el-text tag="b" size="large" style="margin-left: 15px;">供应商{{ state.supplierName }}</el-text>
</el-col>
</el-row>
</el-card>
</div>
<div class="head-container">
<el-card shadow="never">
<el-table @selection-change="handleSelectionChange" v-loading="state.tableData.loading"
:data="state.tableData.list">
<el-table-column type="selection" width="55" />
<el-table-column prop="id" label="ID" width="80" />
<el-table-column label="耗材信息">
<template v-slot="scope">
<div>{{ scope.row.conName }}</div>
<div>单价{{ scope.row.purchasePrice }}</div>
<div>入库数量{{ scope.row.inOutNumber }}</div>
</template>
</el-table-column>
<el-table-column prop="amountPayable" label="账单金额" width="120" />
<el-table-column prop="actualPaymentAmount" label="已付款金额" width="120" />
<el-table-column prop="unPaidAmount" label="未付款金额" width="120" />
<el-table-column prop="createTime" label="创建时间" width="120" />
<el-table-column prop="remark" label="备注" />
<el-table-column label="操作" width="200">
<template v-slot="scope">
<el-button type="primary" size="small" link @click="handlePayment(scope.row)">
付款
</el-button>
<el-button type="primary" size="small" link @click="handleRecord(scope.row.id)">
付款记录
</el-button>
</template>
</el-table-column>
</el-table>
</el-card>
</div>
<div class="head-container">
<el-pagination v-model:current-page="state.tableData.page" v-model:page-size="state.tableData.size"
:total="state.tableData.total" :page-sizes="[10, 20, 30, 50, 100]"
layout="total, sizes , prev, pager ,next, jumper " @current-change="paginationChange" />
</div>
<payment ref="refPayment" @refresh="getTableData"></payment>
</div>
</template>
<script setup>
import AuthAPI from "@/api/supplier/index";
import payment from "./components/payment.vue";
import { ElMessage } from "element-plus";
const route = useRoute();
const router = useRouter();
const state = reactive({
query: {
name: "",
vendorId: null,
},
tableData: {
list: [],
page: 1,
size: 10,
loading: false,
total: 0,
},
supplierName: '',
flowIdList: [],
allAmount: 0
});
onMounted(() => {
if (route.query.vendorId) {
state.query.vendorId = route.query.vendorId
}
if (route.query.supplierName) {
state.supplierName = route.query.supplierName
}
getTableData();
});
// 获取账单记录列表
async function getTableData() {
state.tableData.loading = true;
try {
const res = await AuthAPI.getRecordList({
page: state.tableData.page,
size: state.tableData.size,
key: state.query.name,
vendorId: state.query.vendorId,
});
state.tableData.loading = false;
state.tableData.list = res.records;
state.tableData.total = res.totalRow * 1;
} catch (error) {
console.log(error);
}
}
const refPayment = ref();
function handlePayment(item) {
if (item != 'all') {
state.flowIdList = [item.id]
state.allAmount = item.unPaidAmount
} else {
if( state.flowIdList.length <= 0 ){
ElMessage({ type: "error", message: "请选择付款耗材" });
return;
}
}
refPayment.value.open({ flowIdList: state.flowIdList, supplierName: state.supplierName,allAmount:state.allAmount });
}
function handleSelectionChange(e) {
state.flowIdList = []
state.allAmount = 0
e.map(item => {
state.flowIdList.push(item.id)
state.allAmount += item.unPaidAmount
})
}
// 付款记录
function handleRecord(id) {
router.push({ name: "financePaymentRecord", query: { id: id, supplierName: state.supplierName } });
}
// 重置查询
function resetHandle() {
state.query.name = "";
getTableData();
}
// 分页回调
function paginationChange(e) {
state.tableData.page = e;
getTableData();
}
</script>
<style scoped lang="scss">
.head-container {
margin-bottom: 20px;
}
.shop_info {
display: flex;
.info {
flex: 1;
padding-left: 4px;
}
}
.el-link {
min-height: 23px;
margin: 0 5px;
}
</style>

View File

@@ -1,84 +0,0 @@
<template>
<!-- 修改和增加 -->
<el-dialog title="付款" v-model="show" width="400px" @close="reset">
<el-form :inline="false" ref="refform" label-width="90" :model="form" :rules="rules" class="demo-form-inline">
<el-form-item label="供应商">
<el-input v-model="supplierName" placeholder="请输入供应商名称" readonly></el-input>
</el-form-item>
<el-form-item label="付款金额 " prop="amount">
<el-input-number v-model="form.amount" :readonly="form.flowIdList.length > 1" :max="maxAmount" placeholder="请输入付款金额"
style="width: 100%;"></el-input-number>
</el-form-item>
<el-form-item label="付款方式" prop="type">
<el-input v-model="form.type" placeholder="请输入付款方式"></el-input>
</el-form-item>
<el-form-item label="备注" prop="remark">
<el-input v-model="form.remark" placeholder="请输入备注"></el-input>
</el-form-item>
<el-form-item style="display: flex; justify-content: flex-end">
<el-button @click="close"> </el-button>
<el-button type="primary" @click="submitForm('refform')"> </el-button>
</el-form-item>
</el-form>
</el-dialog>
</template>
<script setup>
import AuthAPI from "@/api/supplier/index";
import { ElMessage } from "element-plus";
const emits = defineEmits(["refresh"]);
const rules = {
amount: [{ required: true, message: "请输入付款金额", trigger: "blur" }],
type: [{ required: true, message: "请输入付款方式", trigger: "blur" }],
};
const basicForm = {
flowIdList: [],
amount: undefined,
type: '',
remark: '',
};
const form = reactive({
...basicForm,
});
const supplierName = ref('');
const maxAmount = ref(0);
const show = ref(false);
function open(item) {
form.flowIdList = item.flowIdList
supplierName.value = item.supplierName
form.amount = item.allAmount
maxAmount.value = item.allAmount
// Object.assign(form, item);
show.value = true;
}
function close() {
show.value = false;
}
const refform = ref();
async function submitForm() {
refform.value.validate(async (valid) => {
if (valid) {
const res = await AuthAPI.billPay(form);
ElMessage({ type: "success", message: "付款成功" });
emits("refresh");
close();
}
});
}
function reset() {
console.log("reset");
Object.assign(form, basicForm);
close();
}
defineExpose({
open,
close,
});
</script>

View File

@@ -1,148 +0,0 @@
<template>
<div class="app-container">
<div class="head-container">
<el-card shadow="never">
<el-alert title="当前列表仅作为数据记录,不产生任何实际交易。" type="warning" show-icon :closable="false"
style="margin-bottom: 15px;" />
<el-row :gutter="20">
<el-col :span="4">
<el-input v-model="state.query.name" clearable placeholder="请输入供应商名称" style="width: 100%"
class="filter-item" @keyup.enter="getTableData" />
</el-col>
<el-col :span="16">
<el-button type="primary" @click="getTableData">查询</el-button>
</el-col>
</el-row>
</el-card>
</div>
<div class="head-container">
<el-card shadow="never">
<el-row :gutter="24">
<el-col :span="8" style="display: flex;flex-direction: column; justify-content: center;align-items: center;">
<div>账单总金额全部/本月</div>
<div>{{ state.summaryData.amountPayable || 0 }} / {{ state.summaryData.mouthAmountPayable || 0 }}</div>
</el-col>
<el-col :span="8" style="display: flex;flex-direction: column; justify-content: center;align-items: center;">
<div>已付款总金额全部/本月</div>
<div>{{ state.summaryData.actualPaymentAmount || 0 }} / {{ state.summaryData.mouthActualPaymentAmount || 0 }}</div>
</el-col>
<el-col :span="8" style="display: flex;flex-direction: column; justify-content: center;align-items: center;">
<div>未付款总金额全部/本月</div>
<div>{{ state.summaryData.unPaidAmount || 0 }} / {{ state.summaryData.mouthUnPaidAmount || 0 }}</div>
</el-col>
</el-row>
</el-card>
</div>
<div class="head-container">
<el-card shadow="never">
<el-table v-loading="state.tableData.loading" :data="state.tableData.list">
<el-table-column prop="name" label="供应商" width="220" />
<el-table-column prop="amountPayable" label="账单金额" width="200" />
<el-table-column prop="actualPaymentAmount" label="已付款金额" width="200" />
<el-table-column prop="unPaidAmount" label="未付款金额" width="200" />
<el-table-column prop="remark" label="备注" />
<el-table-column label="操作" width="120">
<template v-slot="scope">
<el-button type="primary" size="small" link @click="handleTo(scope.row)">
账单记录
</el-button>
</template>
</el-table-column>
</el-table>
</el-card>
</div>
<div class="head-container">
<el-pagination v-model:current-page="state.tableData.page" v-model:page-size="state.tableData.size"
:total="state.tableData.total" :page-sizes="[10, 20, 30, 50, 100]"
layout="total, sizes , prev, pager ,next, jumper " @current-change="paginationChange" />
</div>
</div>
</template>
<script setup>
import AuthAPI from "@/api/supplier/index";
const router = useRouter();
const state = reactive({
query: {
name: "",
},
summaryData: {},
tableData: {
list: [],
page: 1,
size: 10,
loading: false,
total: 0,
},
});
onMounted(() => {
getSummary();
getTableData();
});
async function getSummary() {
try {
const res = await AuthAPI.getSummary();
state.summaryData = res;
} catch (error) {
console.log(error);
}
}
// 获取账单列表
async function getTableData() {
state.tableData.loading = true;
try {
const res = await AuthAPI.getPage({
page: state.tableData.page,
size: state.tableData.size,
key: state.query.name,
});
state.tableData.loading = false;
state.tableData.list = res.records;
state.tableData.total = res.totalRow * 1;
} catch (error) {
console.log(error);
}
}
function handleTo(row) {
// router.push({ path: "/finance/supplierBill/billingRecord", query: { id: e.id } });
router.push({ name: "financeBillingRecord", query: { vendorId: row.vendorId, supplierName: row.name } });
}
// 重置查询
function resetHandle() {
state.query.name = "";
getTableData();
}
// 分页回调
function paginationChange(e) {
state.tableData.page = e;
getTableData();
}
</script>
<style scoped lang="scss">
.head-container {
margin-bottom: 20px;
}
.shop_info {
display: flex;
.info {
flex: 1;
padding-left: 4px;
}
}
.el-link {
min-height: 23px;
margin: 0 5px;
}
</style>

View File

@@ -1,137 +0,0 @@
<template>
<div class="app-container">
<div class="head-container">
<el-card shadow="never">
<el-alert title="当前列表仅作为数据记录,不产生任何实际交易。" type="warning" show-icon :closable="false"
style="margin-bottom: 15px;" />
<el-text tag="b" size="large" style="margin-left: 15px;">供应商{{ state.supplierName }}</el-text>
</el-card>
</div>
<div class="head-container">
<el-card shadow="never">
<el-table v-loading="state.tableData.loading" :data="state.tableData.list">
<el-table-column prop="id" label="ID" width="80" />
<el-table-column label="耗材信息">
<template v-slot="scope">
<div>{{ scope.row.conName }}</div>
<div>单价{{ scope.row.purchasePrice }}</div>
<div>入库数量{{ scope.row.inOutNumber }}</div>
</template>
</el-table-column>
<el-table-column prop="amount" label="付款金额" width="120" />
<el-table-column prop="type" label="付款方式" width="120" />
<el-table-column prop="remark" label="备注" />
<el-table-column prop="createTime" label="创建时间" />
<el-table-column label="操作人" width="200">
<template v-slot="scope">
<div>员工名称{{ scope.row.nickname }}</div>
<div>员工编号{{ scope.row.code }}</div>
<div>员工账号{{ scope.row.account }}</div>
</template>
</el-table-column>
</el-table>
</el-card>
</div>
<div class="head-container">
<el-pagination v-model:current-page="state.tableData.page" v-model:page-size="state.tableData.size"
:total="state.tableData.total" :page-sizes="[10, 20, 30, 50, 100]"
layout="total, sizes , prev, pager ,next, jumper " @current-change="paginationChange" />
</div>
</div>
</template>
<script setup>
import ShopApi from "@/api/account/shop";
import AuthAPI from "@/api/supplier/index";
import { ElMessageBox } from "element-plus";
const route = useRoute();
const state = reactive({
query: {
name: "",
flowId: null,
},
tableData: {
list: [],
page: 1,
size: 10,
loading: false,
total: 0,
},
supplierName: '',
});
onMounted(() => {
console.log(route.query);
if (route.query.id) {
state.query.flowId = route.query.id
}
if (route.query.supplierName) {
state.supplierName = route.query.supplierName
}
getTableData();
});
// 获取账单付款列表
async function getTableData() {
state.tableData.loading = true;
try {
const res = await AuthAPI.getPayRecordList({
page: state.tableData.page,
size: state.tableData.size,
flowId: state.query.flowId,
});
state.tableData.loading = false;
state.tableData.list = res.records;
state.tableData.total = res.totalRow * 1;
} catch (error) {
console.log(error);
}
}
function handleSync(e) {
console.log(e)
ElMessageBox.confirm(`同步功能开启后不能关闭,请确认是否给${e.shopName}开启同步?`, "提示", {
confirmButtonText: "确认",
cancelButtonText: "取消",
type: "warning",
}).then(async () => {
const res = await ShopApi.delete({ id: row.id });
ElMessage({
type: "success",
message: "同步成功",
});
getTableData();
}).catch(() => { });
}
// 重置查询
function resetHandle() {
state.query.name = "";
getTableData();
}
// 分页回调
function paginationChange(e) {
state.tableData.page = e;
getTableData();
}
</script>
<style scoped lang="scss">
.head-container {
margin-bottom: 20px;
}
.shop_info {
display: flex;
.info {
flex: 1;
padding-left: 4px;
}
}
.el-link {
min-height: 23px;
margin: 0 5px;
}
</style>

View File

@@ -20,15 +20,7 @@ const contentConfig: IContentConfig = {
return Api.edit(data);
},
pk: "id",
toolbar: [
{
icon: "plus",
text: "新增",
type: "primary",
name: "add",
auth: "import",
},
],
toolbar: ["add"],
defaultToolbar: ["refresh", "filter", "search"],
cols: [
// { type: "selection", width: 50, align: "center" },
@@ -57,7 +49,7 @@ const contentConfig: IContentConfig = {
fixed: "right",
width: 280,
templet: "tool",
operat: [{ text: "编辑", icon: 'edit', name: "edit"}],
operat: ["edit"],
},
],
};

View File

@@ -71,7 +71,6 @@ import contentConfig from "./config/content";
import editModalConfig from "./config/edit";
import searchConfig from "./config/search";
import { returnOptionsLabel } from "./config/config";
import { isSyncStatus } from "@/utils/index";
const {
searchRef,
@@ -88,14 +87,6 @@ const {
handleFilterChange,
} = usePage();
if (isSyncStatus()) {
contentConfig.toolbar[0].hidden = true
contentConfig.cols[contentConfig.cols.length - 1].operat[0].hidden = true
} else {
contentConfig.toolbar[0].hidden = false
contentConfig.cols[contentConfig.cols.length - 1].operat[0].hidden = false
}
// 新增
async function handleAddClick() {
addModalRef.value?.setModalVisible();

View File

@@ -77,40 +77,8 @@
</div>
</div>
</div>
<!--<div style="
width: 200px;
flex-direction: column;
justify-content: center;
align-items: center;
background: #fff;
">
<div style="font-weight: bold">入库</div>
<div style="margin-top: 10px">{{ data.stockInNum || 0 }}</div>
<div style="margin-top: 10px">{{ data.totalRow || 0 }}</div>
</div>
<div style="
width: 200px;
flex-direction: column;
justify-content: center;
align-items: center;
background: #fff;
">
<div style="font-weight: bold">出库</div>
<div style="margin-top: 10px">{{ data.stockOutNum || 0 }}</div>
<div style="margin-top: 10px">{{ data.totalRow || 0 }}</div>
</div>
<div style="
width: 200px;
flex-direction: column;
justify-content: center;
align-items: center;
background: #fff;
">
<div style="font-weight: bold">报损</div>
<div style="margin-top: 10px">{{ data.damageNum || 0 }}</div>
<div style="margin-top: 10px">{{ data.totalRow || 0 }}</div>
</div> -->
<stockHistory ref="refStockHistory" />
<stockHistory ref="refStockHistory"></stockHistory>
</div>
</template>
<script setup>
@@ -129,6 +97,7 @@ function refStockHistoryShow(key) {
}
</script>
<style scoped lang="scss">
.DataStatistics {
border: 1px solid #e4e7ed;
@@ -141,7 +110,7 @@ function refStockHistoryShow(key) {
align-items: center;
justify-content: space-around;
>div {
> div {
height: 80px;
background-color: #f4f9ff;
display: flex;
@@ -161,7 +130,6 @@ function refStockHistoryShow(key) {
span {
color: #666;
font-size: 14px;
&.num {
color: #3f9eff;
cursor: pointer;
@@ -169,4 +137,4 @@ function refStockHistoryShow(key) {
}
}
}
</style>
</style>

View File

@@ -0,0 +1,197 @@
<template>
<!-- 修改和增加 -->
<el-dialog :title="dialogtitle" v-model="show" width="85%">
<div v-if="dialogtitle != '编辑'">
<div v-for="(item, index) in forms" :key="index">
<el-form
:inline="true"
:ref="(el) => setFormRef(el, index)"
:model="item"
:rules="rules"
class="demo-form-inline"
>
<el-form-item label=" ">
<el-icon color="red" @click="formsReduce(index)"><Remove /></el-icon>
</el-form-item>
<el-form-item label="耗材名称" prop="conName">
<el-input v-model="item.conName" placeholder="请输入耗材信息名称"></el-input>
</el-form-item>
<el-form-item label="耗材类型" prop="conTypeId">
<el-select v-model="item.conTypeId" placeholder="请选择耗材类型" style="width: 200px">
<el-option
v-for="option in consGroups"
:key="option.conTypeId"
:label="option.conTypeName"
:value="option.id"
></el-option>
</el-select>
</el-form-item>
<el-form-item label="单位" prop="conUnit">
<el-input v-model="item.conUnit" placeholder="请输入单位"></el-input>
</el-form-item>
<el-form-item label="耗材价格">
<el-input v-model="item.price" placeholder="请输入耗材价格"></el-input>
</el-form-item>
<el-form-item label="预警值">
<el-input v-model="item.conWarning" placeholder="请输入耗材预警值"></el-input>
</el-form-item>
<el-form-item label=" ">
<el-icon color="green" @click="formsAdd(index)"><CirclePlus /></el-icon>
</el-form-item>
</el-form>
</div>
<div style="display: flex; justify-content: flex-end">
<el-button @click="dialogshow = false"> </el-button>
<el-button type="primary" @click="submitForms()"> </el-button>
</div>
</div>
<el-form
v-else
:inline="true"
ref="refform"
:model="form"
:rules="rules"
class="demo-form-inline"
>
{{ dialogtitle }}
<el-form-item label="耗材信息名称" prop="conName">
<el-input v-model="form.conName" placeholder="请输入耗材信息名称"></el-input>
</el-form-item>
<el-form-item label="耗材价格">
<el-input v-model="form.price" placeholder="请输入耗材价格"></el-input>
</el-form-item>
<el-form-item label="单位" prop="conUnit">
<el-input v-model="form.conUnit" placeholder="请输入单位"></el-input>
</el-form-item>
<el-form-item label="预警值">
<el-input v-model="form.conWarning" placeholder="请输入耗材预警值"></el-input>
</el-form-item>
<!-- <el-form-item label="状态" v-if="dialogtitle == '编辑'">
<el-switch v-model="form.status" active-value="1" inactive-value="0"></el-switch>
</el-form-item> -->
<!-- <el-form-item label="单位耗材值" prop="surplusStock">
<el-input v-model="form.surplusStock" placeholder="请输入单位耗材值"></el-input>
</el-form-item> -->
<el-form-item style="display: flex; justify-content: flex-end">
<el-button @click="dialogshow = false"> </el-button>
<el-button type="primary" @click="submitForm('refform')"> </el-button>
</el-form-item>
</el-form>
</el-dialog>
</template>
<script setup>
import consApi from "@/api/product/cons";
import consGroupApi from "@/api/product/cons-group";
import { ElMessage } from "element-plus";
const consGroups = ref([]);
const rules = {
conCode: [{ required: true, message: "请输入耗材信息代码", trigger: "blur" }],
conName: [{ required: true, message: "请输入耗材信息名称", trigger: "blur" }],
conTypeId: [{ required: true, message: "请选择耗材类型", trigger: "change" }],
price: [{ required: true, message: "请输入耗材价格", trigger: "blur" }],
conWarning: [{ required: true, message: "请输入耗材预警值", trigger: "blur" }],
conTypeId: [{ required: true, message: "请输入耗材类型id", trigger: "blur" }],
conUnit: [{ required: true, message: "请输入单位", trigger: "blur" }],
conWarning: [
{
required: true,
message: "请输入单位",
trigger: "blur",
},
],
};
function getConsGroups() {
consGroupApi.getAllList().then((res) => {
consGroups.value = res.map((v) => {
return {
...v,
label: v.name,
value: v.id,
};
});
});
}
getConsGroups();
const basicForm = {
conCode: "",
conName: "",
conTypeId: "",
price: "0",
conNames: "",
conUnit: "",
conWarning: "999",
shopId: localStorage.getItem("shopId"),
status: "",
};
const forms = ref([{ ...basicForm }]);
const form = reactive({
...basicForm,
});
const show = ref(false);
let dialogtitle = ref("");
function open(item) {
dialogtitle.value = item ? "编辑" : "新增";
show.value = true;
}
function formsAdd(index) {
forms.value.push({ ...basicForm });
}
function close() {
show.value = false;
}
const refForms = ref([]);
function setFormRef(el, index) {
if (el) {
refForms.value[index] = el;
}
}
function returnPromise(index, prosise) {
return new Promise((resolve, reject) => {
prosise
.then((res) => {
console.log(res);
resolve({ sucees: true });
})
.catch((err) => {
console.log(err);
resolve({ sucees: false });
});
});
}
async function submitForms() {
let isAllPassForm = 0;
for (let i in this.forms) {
console.log(refForms.value[i]);
const res = await returnPromise(i, refForms.value[i].validate());
console.log(res);
isAllPassForm += res.sucees ? 1 : 0;
}
//判断验证是否通过
if (isAllPassForm === this.forms.length) {
await consApi.add(this.forms);
ElMessage({ type: "success", message: "添加成功" });
// for(let i of this.forms){
// const res=await posttbConsInfo(i)
// this.$message({ type: "success", message: "添加成功" });
// }
this.dialogshow = false;
this.resetRuleForms();
this.ruleFormLoading = false;
this.getTableData();
}
}
defineExpose({
open,
close,
});
</script>

View File

@@ -13,11 +13,11 @@ const contentConfig: IContentConfig = {
pageSizes: [10, 20, 30, 50],
},
indexAction: function (params) {
let obj = { ...params };
let obj = { ...params }
if (obj.createAt) {
obj.beginTime = obj.createAt[0];
obj.endTime = obj.createAt[1];
delete obj.createAt;
obj.beginTime = obj.createAt[0]
obj.endTime = obj.createAt[1]
delete obj.createAt
}
return Api.getList(obj);
},
@@ -25,62 +25,28 @@ const contentConfig: IContentConfig = {
// modifyAction: function (data) {
// // return Api.edit(data);
// },
indexActionData: {},
pk: "id",
toolbar: [
{
icon: "plus",
text: "新增",
type: "primary",
name: "add",
auth: "import",
},
{
icon: "refresh",
text: "同步",
type: "danger",
name: "sync",
auth: "import",
},
"add",
{
text: "入库",
name: "ruku",
auth: "ruku",
name: 'ruku',
auth: 'ruku'
},
{
text: "出库",
name: "chuku",
auth: "",
name: 'chuku',
auth: ''
},
{
text: "分类管理",
name: "category",
auth: "",
name: 'category',
auth: ''
},
{
text: "供应商管理",
name: "gongyinsahng",
auth: "",
},
{
text: "入库记录",
name: "manual-in",
auth: "",
},
{
text: "出库记录",
name: "manual-out",
auth: "",
},
{
text: "报损记录",
name: "damage-out",
auth: "",
},
{
text: "报损",
name: "reportinglosses",
auth: "",
name: 'gongyinsahng',
auth: ''
},
],
defaultToolbar: ["refresh", "filter", "search"],
@@ -102,8 +68,8 @@ const contentConfig: IContentConfig = {
{
label: "所属商品",
align: "center",
templet: "custom",
slotName: "goods",
templet: 'custom',
slotName: 'goods'
},
{
label: "库存数量",
@@ -128,7 +94,7 @@ const contentConfig: IContentConfig = {
fixed: "right",
width: 150,
templet: "custom",
slotName: "operate",
slotName: 'operate'
},
],
};

View File

@@ -1,5 +1,5 @@
import type { ISearchConfig } from "@/components/CURD/types";
import consGroupApi from "@/api/product/cons-group";
import consGroupApi from '@/api/product/cons-group'
import { statusOptions, payTypeOptions } from "./config";
const searchConfig: ISearchConfig = {
pageName: "sys:user",
@@ -20,14 +20,14 @@ const searchConfig: ISearchConfig = {
initialValue: "",
initFn(formItem) {
console.log(formItem);
consGroupApi.getAllList({}).then((res) => {
formItem.options = res.map((item: { name: any; id: any }) => {
consGroupApi.getAllList({}).then(res => {
formItem.options = res.map((item: { name: any; id: any; }) => {
return {
label: item?.name,
value: item?.id,
};
});
});
value: item?.id
}
})
})
},
},
@@ -42,23 +42,22 @@ const searchConfig: ISearchConfig = {
width: "200px",
},
},
initialValue: "",
},
// {
// type: "date-picker",
// label: "创建时间",
// prop: "createAt",
// attrs: {
// type: "daterange",
// "range-separator": "~",
// "start-placeholder": "开始时间",
// "end-placeholder": "截止时间",
// "value-format": "YYYY-MM-DD",
// style: {
// width: "240px",
// },
// },
// },
{
type: "date-picker",
label: "创建时间",
prop: "createAt",
attrs: {
type: "daterange",
"range-separator": "~",
"start-placeholder": "开始时间",
"end-placeholder": "截止时间",
"value-format": "YYYY-MM-DD",
style: {
width: "240px",
},
},
},
],
};

View File

@@ -2,14 +2,26 @@
<div class="app-container">
<!-- 列表 -->
<!-- 搜索 -->
<page-search ref="searchRef" :search-config="searchConfig" @query-click="newHandleQueryClick"
@reset-click="handleResetClick" />
<page-search
ref="searchRef"
:search-config="searchConfig"
@query-click="newHandleQueryClick"
@reset-click="handleResetClick"
/>
<!-- 统计 -->
<data-tongji :data="gongjiData" />
<data-tongji :data="gongjiData"></data-tongji>
<!-- 列表 -->
<page-content ref="contentRef" :content-config="contentConfig" @add-click="handleAddClick"
@edit-click="handleEditClick" @export-click="handleExportClick" @search-click="handleSearchClick"
@toolbar-click="handleToolbarClick" @operat-click="handleOperatClick" @filter-change="handleFilterChange">
<page-content
ref="contentRef"
:content-config="contentConfig"
@add-click="handleAddClick"
@edit-click="handleEditClick"
@export-click="handleExportClick"
@search-click="handleSearchClick"
@toolbar-click="handleToolbarClick"
@operat-click="handleOperatClick"
@filter-change="handleFilterChange"
>
<template #status="scope">
<el-tag :type="scope.row[scope.prop] == 1 ? 'success' : 'info'">
{{ scope.row[scope.prop] == 1 ? "启用" : "禁用" }}
@@ -21,22 +33,28 @@
<template #goods="scope">
<div class="goodslang">
<div class="goods-list">
<el-button v-for="item in scope.row.productList" :key="item.productId" type="text"
@click="toGoods(item.id)">
<el-button
v-for="item in scope.row.productList"
@click="toGoods(item.id)"
:key="item.productId"
type="text"
>
{{ item.name }}
</el-button>
<span v-if="scope.row.productList.length > 1">,</span>
</div>
<el-dropdown v-if="scope.row.productList.length > 1" trigger="click" @command="toGoods">
<el-dropdown trigger="click" v-if="scope.row.productList.length > 1" @command="toGoods">
<span class="el-dropdown-link" style="color: blue">
<el-icon>
<CaretBottom />
</el-icon>
<el-icon><CaretBottom /></el-icon>
</span>
<template #dropdown>
<el-dropdown-menu>
<el-dropdown-item v-for="item in scope.row.productList" :key="item.id" class="clearfix"
:command="item.id">
<el-dropdown-item
class="clearfix"
v-for="item in scope.row.productList"
:key="item.id"
:command="item.id"
>
{{ item.name }}
</el-dropdown-item>
</el-dropdown-menu>
@@ -55,34 +73,25 @@
</template>
<template #mobile="scope">
<el-text>{{ scope.row[scope.prop] }}</el-text>
<copy-button v-if="scope.row[scope.prop]" :text="scope.row[scope.prop]" style="margin-left: 2px" />
<copy-button
v-if="scope.row[scope.prop]"
:text="scope.row[scope.prop]"
style="margin-left: 2px"
/>
</template>
<template #operate="scope">
<div style="
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
">
<el-button v-if="!isSyncStatus()" type="primary" link @click="refAddHaocaiOpen(scope.row)">
编辑
</el-button>
<el-button link type="primary" @click="refAddHaocaiTakinShow(scope.row, 'consumables')">
<div>
<el-button @click="refAddHaocaiOpen(scope.row)" type="primary" link>编辑</el-button>
<el-button @click="refAddHaocaiTakinShow(scope.row)" link type="primary">
耗材盘点
</el-button>
<el-button link type="primary" @click="refAddHaocaiTakinShow(scope.row, 'manual-in')">
入库记录
</el-button>
<!-- <el-button link type="primary" @click="refAddHaocaiTakinShow(scope.row, 'delete')">
删除
</el-button> -->
</div>
</template>
</page-content>
<!-- 耗材添加编辑 -->
<add-haocai ref="refAddHaocai" @refresh="refresh" />
<add-haocai ref="refAddHaocai" @refresh="refresh"></add-haocai>
<!-- 耗材盘点 -->
<addConsTakin ref="refAddHaocaiTakin" @success="refresh" />
<addConsTakin ref="refAddHaocaiTakin" @success="refresh"></addConsTakin>
</div>
</template>
@@ -91,16 +100,12 @@ import addHaocai from "./components/add-haocai.vue";
import dataTongji from "./components/DataStatistics.vue";
import addConsTakin from "./components/addConsTakin.vue";
import consApi from "@/api/product/cons";
import UserAPI from "@/api/product/index";
import type { IObject, IOperatData } from "@/components/CURD/types";
import usePage from "@/components/CURD/usePage";
import contentConfig from "./config/content";
import editModalConfig from "./config/edit";
import searchConfig from "./config/search";
import { returnOptionsLabel } from "./config/config";
import { isSyncStatus } from "@/utils/index";
const router = useRouter();
const {
searchRef,
@@ -118,24 +123,6 @@ function toGoods(id: number | string) {
router.push({ path: "/product/index", query: { id: id } });
}
// 默认初始数据
const route = useRoute();
const { conName } = route.query;
if (conName) {
contentConfig.indexActionData = { conName };
if (conName) {
searchConfig.formItems[1].initialValue = conName;
}
}
if (isSyncStatus()) {
contentConfig.toolbar[0].hidden = true;
contentConfig.toolbar[1].hidden = false;
} else {
contentConfig.toolbar[0].hidden = false;
contentConfig.toolbar[1].hidden = true;
}
//统计数据
const gongjiData = reactive({ totalRow: 0 });
function getTongji(params: IObject | undefined) {
@@ -165,20 +152,7 @@ watch(
//耗材盘点
const refAddHaocaiTakin = ref();
function refAddHaocaiTakinShow(item: any, type: string) {
console.log(item);
if (type === "manual-in") {
router.push({ path: "/inventory/libraryrecords", query: { inOutItem: type, conId: item.id } });
return;
}
if (type === "delete") {
refAddHaocaiTakin.value.show(item, type);
return;
}
if (type === "consumables") {
refAddHaocaiTakin.value.show(item, type);
return;
}
function refAddHaocaiTakinShow(item: any) {
refAddHaocaiTakin.value.show(item);
}
@@ -203,13 +177,8 @@ async function handleEditClick(row: IObject) {
editModalRef.value?.setFormData({ ...row, url: [row.url] });
}
// 其他工具栏
async function handleToolbarClick(name: string) {
function handleToolbarClick(name: string) {
console.log(name);
if (name === "sync") {
let res = await UserAPI.sync();
ElMessage.success("操作成功,数据正在后台同步中...");
return;
}
if (name === "category") {
router.push({ path: "/inventory/classification" });
return;
@@ -226,14 +195,6 @@ async function handleToolbarClick(name: string) {
router.push({ path: "/inventory/operation_in", query: { type: "out" } });
return;
}
if (name == "reportinglosses") {
router.push({ path: "/inventory/operation_in", query: { type: "reportinglosses" } });
return;
}
if (name == "damage-out" || name == "manual-out" || name == "manual-in") {
router.push({ path: "/inventory/libraryrecords", query: { inOutItem: name } });
return;
}
}
// 其他操作列
async function handleOperatClick(data: IOperatData) {

View File

@@ -1,77 +0,0 @@
import Api from "@/api/product/vendor";
import { returnOptions, switchAttr } from "./config";
import type { IModalConfig } from "@/components/CURD/types";
const modalConfig: IModalConfig = {
pageName: "sys:user",
dialog: {
title: "添加供应商",
width: 800,
draggable: true,
},
form: {
labelWidth: 140,
},
formAction: function (data) {
return Api.add({ ...data });
},
beforeSubmit(data) {
console.log("提交之前处理", data);
},
formItems: [
{
label: "名称",
prop: "name",
rules: [{ required: true, message: "请输入名称", trigger: "blur" }],
attrs: {
placeholder: "请输入名称",
},
},
{
label: "联系人名字",
prop: "contactName",
rules: [{ required: false, message: "请输入联系人名字", trigger: "blur" }],
attrs: {
placeholder: "请输入联系人名字",
},
},
{
label: "联系人电话",
prop: "telephone",
rules: [{ required: false, message: "请输入联系人名字", trigger: "blur" }],
attrs: {
placeholder: "请输入联系人名字",
},
},
{
label: "供应商地址",
prop: "address",
rules: [{ required: false, message: "请输入供应商地址", trigger: "blur" }],
attrs: {
placeholder: "请输入供应商地址",
},
},
{
label: "备注",
prop: "remark",
rules: [{ required: false, message: "请输入备注", trigger: "blur" }],
attrs: {
placeholder: "请输入备注",
},
},
{
label: "排序",
prop: "sort",
rules: [{ required: true, message: "请输入排序", trigger: "blur" }],
type: "input-number",
attrs: {
placeholder: "请输入排序",
},
},
],
};
// 如果有异步数据会修改配置的推荐用reactive包裹而纯静态配置的可以直接导出
export default reactive(modalConfig);

View File

@@ -1,46 +0,0 @@
export interface options {
label: string;
value: string | number;
[property: string]: any;
}
export interface optionObject {
[property: string]: options[];
}
const options: optionObject = {
payType: [
{ label: "现金", value: "cash" },
{ label: "微信", value: "weixin" },
{ label: "银行卡", value: "bank" },
{ label: "会员支付", value: "member-account" },
{ label: "支付宝", value: "alipay" },
{ label: "刷卡", value: "deposit" },
{ label: "挂账", value: "arrears" },
{ label: "刷卡", value: "deposit" },
{ label: "储值", value: "member-account" },
{ label: "自定义", value: "virtual" },
],
isIdeal: [
{ label: "否", value: 0 },
{ label: "是", value: 1 },
],
};
export const switchAttr = {
"active-value": 1,
"inactive-value": 0,
};
export type optionsType = string;
export function returnOptions(type: optionsType) {
return options[type];
}
export function returnOptionsLabel(optionsType: optionsType, value: string | number) {
const options = returnOptions(optionsType);
if (!options) {
return "";
}
const option = options.find((item) => item.value === value);
return option ? option.label : "";
}

View File

@@ -1,94 +0,0 @@
import Api from "@/api/product/libraryrecords";
import type { IContentConfig } from "@/components/CURD/types";
const contentConfig: IContentConfig = {
pageName: "sys:user",
table: {
border: true,
highlightCurrentRow: true,
},
pagination: {
background: true,
layout: "prev,pager,next,jumper,total,sizes",
pageSize: 20,
pageSizes: [10, 20, 30, 50],
},
indexAction: function (params) {
return Api.getList(params);
},
deleteAction: function (id) {
return Api.delete(id);
},
modifyAction: function (data) {
return Api.edit(data);
},
indexActionData: {},
pk: "id",
toolbar: [
// {
// text: "入库记录",
// name: "manual-in",
// auth: "",
// },
// {
// text: "出库记录",
// name: "manual-out",
// auth: "",
// },
// {
// text: "报损记录",
// name: "damage-out",
// auth: "",
// },
],
defaultToolbar: ["refresh", "filter", "search"],
cols: [
// { type: "selection", width: 50, align: "center" },
{
label: "耗材名称",
align: "center",
prop: "conName",
},
{
label: "单位",
align: "center",
prop: "unitName",
},
{
label: "供应商",
align: "center",
prop: "vendorName",
},
{
label: "变动原因",
align: "center",
templet: "custom",
slotName: "conUnit",
},
{
label: "出入库数量",
align: "center",
prop: "inOutNumber",
},
{
label: "变动后的库存",
align: "center",
prop: "afterNumber",
},
{
label: "创建时间",
align: "center",
prop: "createTime",
},
// {
// label: "操作",
// align: "center",
// fixed: "right",
// width: 280,
// templet: "tool",
// operat: ["edit", "delete"],
// },
],
};
export default contentConfig;

View File

@@ -1,75 +0,0 @@
import Api from "@/api/product/vendor";
import { returnOptions, switchAttr } from "./config";
import type { IModalConfig } from "@/components/CURD/types";
const modalConfig: IModalConfig = {
pageName: "sys:user",
dialog: {
title: "编辑供应商",
width: 800,
draggable: true,
},
form: {
labelWidth: 140,
},
formAction: function (data) {
return Api.edit({ ...data });
},
beforeSubmit(data) {
console.log("提交之前处理", data);
},
formItems: [
{
label: "名称",
prop: "name",
rules: [{ required: true, message: "请输入名称", trigger: "blur" }],
attrs: {
placeholder: "请输入名称",
},
},
{
label: "联系人名字",
prop: "contactName",
rules: [{ required: false, message: "请输入联系人名字", trigger: "blur" }],
attrs: {
placeholder: "请输入联系人名字",
},
},
{
label: "联系人电话",
prop: "telephone",
rules: [{ required: false, message: "请输入联系人名字", trigger: "blur" }],
attrs: {
placeholder: "请输入联系人名字",
},
},
{
label: "供应商地址",
prop: "address",
rules: [{ required: false, message: "请输入供应商地址", trigger: "blur" }],
attrs: {
placeholder: "请输入供应商地址",
},
},
{
label: "备注",
prop: "remark",
rules: [{ required: false, message: "请输入备注", trigger: "blur" }],
attrs: {
placeholder: "请输入备注",
},
},
{
label: "排序",
prop: "sort",
rules: [{ required: true, message: "请输入排序", trigger: "blur" }],
type: "input-number",
attrs: {
placeholder: "请输入排序",
},
},
],
};
// 如果有异步数据会修改配置的推荐用reactive包裹而纯静态配置的可以直接导出
export default reactive(modalConfig);

View File

@@ -1,58 +0,0 @@
import type { ISearchConfig } from "@/components/CURD/types";
const searchConfig: ISearchConfig = {
pageName: "sys:user",
isExpandable: false,
formItems: [
{
type: "select",
label: "类型",
prop: "inOutType",
attrs: {
placeholder: "请选择",
clearable: true,
style: {
width: "200px",
},
},
options: [
{
label: "增加",
value: "in",
},
{
label: "减少",
value: "out",
},
],
},
{
type: "select",
label: "名目",
prop: "inOutItem",
attrs: {
placeholder: "请选择",
clearable: true,
style: {
width: "200px",
},
},
options: [
{
label: "入库记录",
value: "manual-in",
},
{
label: "出库记录",
value: "manual-out",
},
{
label: "报损记录",
value: "damage-out",
},
],
initialValue: "",
},
],
};
export default searchConfig;

View File

@@ -1,106 +0,0 @@
<template>
<div class="app-container">
<!-- 搜索 -->
<page-search
ref="searchRef"
:search-config="searchConfig"
@query-click="handleQueryClick"
@reset-click="handleResetClick"
/>
<!-- 列表 -->
<page-content
ref="contentRef"
:content-config="contentConfig"
@add-click="handleAddClick"
@edit-click="handleEditClick"
@export-click="handleExportClick"
@search-click="handleSearchClick"
@toolbar-click="handleToolbarClick"
@operat-click="handleOperatClick"
@filter-change="handleFilterChange"
>
<template #conUnit="scope">
<span v-if="scope.row.inOutItem == 'manual-in'">手动入库</span>
<span v-if="scope.row.inOutItem == 'manual-out'">手动出库</span>
<span v-if="scope.row.inOutItem == 'win-in'">盘盈入库</span>
<span v-if="scope.row.inOutItem == 'loss-out'">盘亏出库</span>
<span v-if="scope.row.inOutItem == 'order-in'">订单退款入库</span>
<span v-if="scope.row.inOutItem == 'order-out'">订单消费出库</span>
</template>
</page-content>
<!-- 新增 -->
<page-modal
ref="addModalRef"
:modal-config="addModalConfig"
@submit-click="handleSubmitClick"
/>
<!-- 编辑 -->
<page-modal
ref="editModalRef"
:modal-config="editModalConfig"
@submit-click="handleSubmitClick"
/>
</div>
</template>
<script setup lang="ts">
import VersionApi from "@/api/system/version";
import type { IObject, IOperatData } from "@/components/CURD/types";
import usePage from "@/components/CURD/usePage";
import addModalConfig from "./config/add";
import contentConfig from "./config/content";
import editModalConfig from "./config/edit";
import searchConfig from "./config/search";
const {
searchRef,
contentRef,
addModalRef,
editModalRef,
handleQueryClick,
handleResetClick,
// handleAddClick,
// handleEditClick,
handleSubmitClick,
handleExportClick,
handleSearchClick,
handleFilterChange,
} = usePage();
// 默认初始数据
const route = useRoute();
const { inOutItem, conId } = route.query;
if (inOutItem || conId) {
contentConfig.indexActionData = { inOutItem, conId };
if (inOutItem) {
searchConfig.formItems[1].initialValue = inOutItem;
}
}
// 新增
async function handleAddClick() {
addModalRef.value?.setModalVisible();
// addModalConfig.formItems[2]!.attrs!.data =
}
// 编辑
async function handleEditClick(row: IObject) {
editModalRef.value?.handleDisabled(false);
editModalRef.value?.setModalVisible();
// 根据id获取数据进行填充
console.log(row);
editModalRef.value?.setFormData({ ...row });
}
// 其他工具栏
function handleToolbarClick(name: string) {
console.log(name);
if (name === "custom1") {
ElMessage.success("点击了自定义1按钮");
}
}
// 其他操作列
async function handleOperatClick(data: IOperatData) {
console.log(data);
}
</script>

View File

@@ -1,12 +1,16 @@
<!-- 耗材列表 -->
<template>
<el-dialog v-model="dialogVisible" title="选择耗材">
<el-dialog title="选择耗材" v-model="dialogVisible">
<el-form :model="searchForm" inline>
<el-form-item>
<el-input v-model="searchForm.conTypeName" placeholder="耗材类型名称" @input="onInput" />
<el-input
v-model="searchForm.conTypeName"
placeholder="耗材类型名称"
@input="onInput"
></el-input>
</el-form-item>
<el-form-item>
<el-input v-model="searchForm.conName" placeholder="耗材名称" @input="onInput" />
<el-input v-model="searchForm.conName" placeholder="耗材名称" @input="onInput"></el-input>
</el-form-item>
<el-form-item>
<el-button type="primary" @click="getTableData">查询</el-button>
@@ -14,13 +18,21 @@
</el-form-item>
</el-form>
<div class="head-container">
<el-table ref="table" v-loading="tableData.loading" :data="tableData.list" :row-key="getRowKey"
@select="firstSelectChange" @selection-change="onSelectionChange">
<el-table-column type="selection" width="55" align="center" />
<el-table-column label="耗材名称" prop="conName" />
<el-table-column label="所属分类" prop="consGroupName" />
<el-table-column label="价格" prop="price" />
<el-table-column label="单位" prop="conUnit" />
<el-table
ref="table"
:data="tableData.list"
v-loading="tableData.loading"
@select="firstSelectChange"
:row-key="getRowKey"
@selection-change="onSelectionChange"
>
<el-table-column type="selection" width="55" align="center"></el-table-column>
<el-table-column label="耗材名称" prop="conName"></el-table-column>
<el-table-column label="价格" prop="price"></el-table-column>
<el-table-column label="耗材代码" prop="conCode"></el-table-column>
<el-table-column label="耗材类型名称" prop="conTypeName"></el-table-column>
<el-table-column label="单位" prop="conUnit"></el-table-column>
<el-table-column label="最近入库量" prop="lasterInStock"></el-table-column>
<el-table-column label="库存数量" prop="stockNumber">
<template v-slot="scope">
{{ formatDecimal(scope.row.stockNumber, 2, true) }}
@@ -33,8 +45,14 @@
</el-table-column> -->
</el-table>
</div>
<el-pagination :total="tableData.total" :current-page="tableData.page + 1" :page-size="tableData.size"
layout="total, sizes, prev, pager, next, jumper" @current-change="paginationChange" @size-change="sizeChange" />
<el-pagination
:total="tableData.total"
:current-page="tableData.page + 1"
:page-size="tableData.size"
@current-change="paginationChange"
@size-change="sizeChange"
layout="total, sizes, prev, pager, next, jumper"
></el-pagination>
<template #footer>
<span class="dialog-footer">
<el-button @click="dialogVisible = false"> </el-button>
@@ -186,4 +204,4 @@ export default {
margin-left: 10px;
}
}
</style>
</style>

View File

@@ -1,81 +1,128 @@
<template>
<div class="app-container bg-fff u-m-20">
<div class="head-container">
<el-form ref="queryForm" :model="queryForm" :rules="queryRules" label-position="left" label-width="100px">
<el-form
ref="queryForm"
:model="queryForm"
:rules="queryRules"
label-position="left"
label-width="100px"
>
<el-row>
<el-form-item label="类型">
<el-radio-group :model-value="type" @change="tabChange">
<el-radio v-if="type == 'reportinglosses'" value="reportinglosses">报损</el-radio>
<div v-else>
<el-radio value="in">入库</el-radio>
<el-radio value="out">出库</el-radio>
</div>
<el-radio-group :model-value="type">
<el-radio-button value="in">入库</el-radio-button>
<el-radio-button value="out">出库</el-radio-button>
</el-radio-group>
</el-form-item>
</el-row>
<div v-if="type != 'reportinglosses'">
<el-row>
<el-col v-if="type == 'in'" :span="8">
<el-form-item label="供应商">
<el-select v-model="queryForm.vendorId" placeholder="请选择供应商" clearable style="width: 220px"
@change="changeTypeEnum">
<el-option v-for="item in purveyorList" :key="item.id" :label="item.name" :value="item.id" />
</el-select>
{{ queryForm.waitAmount }}
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="出入库时间" prop="inOutDate">
<el-date-picker v-model="queryForm.inOutDate" type="date" format="YYYY-MM-DD" value-format="YYYY-MM-DD"
placeholder="选择日期" style="width: 220px" disabled="false" />
</el-form-item>
</el-col>
</el-row>
<el-row>
<el-col :span="8">
<el-form-item label="应付金额">
<el-input v-model="queryForm.amountPayable" placeholder="请输入应收金额" style="width: 220px" />
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="实付金额">
<el-input v-model="queryForm.actualPaymentAmount" placeholder="请输入实收金额" style="width: 220px" />
</el-form-item>
</el-col>
</el-row>
<el-row>
<el-col :span="8">
<el-form-item label="付款时间">
<el-date-picker v-model="queryForm.paymentDate" type="date" format="YYYY-MM-DD"
value-format="YYYY-MM-DD" placeholder="选择日期" style="width: 220px" />
</el-form-item>
</el-col>
<!-- <el-col :span="8">
<el-form-item label="批号">
<el-input v-model="queryForm.batchNo" placeholder="请输入批号" style="width: 220px" />
<el-row>
<el-col :span="8">
<el-form-item label="供应商">
<el-select
v-model="queryForm.vendorId"
placeholder="请选择供应商"
clearable
style="width: 220px"
@change="changeTypeEnum"
>
<el-option
:label="item.name"
:value="item.id"
v-for="item in purveyorList"
:key="item.id"
></el-option>
</el-select>
{{ queryForm.waitAmount }}
</el-form-item>
</el-col> -->
</el-row>
<!-- <el-row>
<el-col :span="8">
<el-form-item label="备注">
<el-input v-model="queryForm.remark" placeholder="请输入备注" style="width: 220px" />
</el-form-item>
</el-col>
</el-row> -->
</div>
</el-col>
<el-col :span="8">
<el-form-item label="出入库时间" prop="inOutDate">
<el-date-picker
v-model="queryForm.inOutDate"
type="date"
format="YYYY-MM-DD"
value-format="YYYY-MM-DD"
placeholder="选择日期"
style="width: 220px"
></el-date-picker>
</el-form-item>
</el-col>
</el-row>
<el-row>
<el-col :span="8">
<el-form-item label="应付金额">
<el-input
v-model="queryForm.amountPayable"
placeholder="请输入应收金额"
style="width: 220px"
></el-input>
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="实付金额">
<el-input
v-model="queryForm.actualPaymentAmount"
placeholder="请输入实收金额"
style="width: 220px"
></el-input>
</el-form-item>
</el-col>
</el-row>
<el-row>
<el-col :span="8">
<el-form-item label="付款时间">
<el-date-picker
v-model="queryForm.paymentDate"
type="date"
format="YYYY-MM-DD"
value-format="YYYY-MM-DD"
placeholder="选择日期"
style="width: 220px"
></el-date-picker>
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="批号">
<el-input
v-model="queryForm.batchNo"
placeholder="请输入批号"
style="width: 220px"
></el-input>
</el-form-item>
</el-col>
</el-row>
<el-row>
<el-col :span="8">
<el-form-item label="备注">
<el-input
v-model="queryForm.remark"
placeholder="请输入备注"
style="width: 220px"
></el-input>
</el-form-item>
</el-col>
</el-row>
<el-form-item label="选择耗材">
<div />
<div></div>
<el-button type="primary" @click="showHaocai">选择耗材</el-button>
<el-autocomplete v-model="autocompletename" :fetch-suggestions="querySearchAsync" value-key="conName"
placeholder="耗材搜索" style="width: 200px; margin-left: 20px" @select="handleSelect" />
<el-autocomplete
v-model="autocompletename"
:fetch-suggestions="querySearchAsync"
value-key="conName"
placeholder="耗材搜索"
@select="handleSelect"
style="width: 200px; margin-left: 20px"
></el-autocomplete>
</el-form-item>
</el-form>
</div>
<div style="font-weight: bold; font-size: 16px; color: #666">
{{ tableData.list.length }}种耗材金额合计
<span style="color: red">{{ amountPayable }}</span>
<div class="head-container">
<el-button type="primary" plain>
{{ tableData.list.length }}种耗材金额合计
<span style="color: red">{{ amountPayable }}</span>
</el-button>
</div>
<div class="head-container">
<el-table :data="tableData.list">
@@ -84,14 +131,13 @@
{{ scope.row.conName }}
</template>
</el-table-column>
<el-table-column label="所属分类">
<el-table-column label="进价">
<template v-slot="scope">
{{ scope.row.consGroupName }}
</template>
</el-table-column>
<el-table-column>
<template v-slot="scope">
<el-input-number v-model="scope.row.price" :min="0" controls-position="right" />
<el-input-number
v-model="scope.row.price"
:min="0"
controls-position="right"
></el-input-number>
<div class="tips" style="font-size: 16px">
原价
@@ -103,17 +149,30 @@
</el-table-column>
<el-table-column label="单位">
<template v-slot="scope">
<el-select v-model="scope.row.unit" :placeholder="scope.row.unit" @change="changeUnit(scope.row)">
<el-option :label="scope.row.conUnit" :value="scope.row.conUnit" />
<el-option v-if="scope.row.conUnitTwo" :label="scope.row.conUnitTwo" :value="scope.row.conUnitTwo" />
<el-select
v-model="scope.row.unit"
:placeholder="scope.row.unit"
@change="changeUnit(scope.row)"
>
<el-option :label="scope.row.conUnit" :value="scope.row.conUnit"></el-option>
<el-option
:label="scope.row.conUnitTwo"
:value="scope.row.conUnitTwo"
v-if="scope.row.conUnitTwo"
></el-option>
</el-select>
<div class="tips">&nbsp;</div>
</template>
</el-table-column>
<el-table-column label="数量">
<template v-slot="scope">
<el-input-number v-model="scope.row.stockNumber" :min="0" :step="1" step-strictly
controls-position="right" />
<el-input-number
v-model="scope.row.stockNumber"
:min="0"
:step="1"
step-strictly
controls-position="right"
></el-input-number>
<div class="tips" style="font-size: 16px">
{{ type == "in" ? "入库" : "出库" }}
{{ returnStockNumber(scope.row, scope.row.number) }}
@@ -122,27 +181,12 @@
</div>
</template>
</el-table-column>
<!-- <el-table-column v-if="type == 'reportinglosses'" label="报损数量">
<el-table-column label="小计">
<template v-slot="scope">
{{ scope.row.number }}
<div class="tips" style="font-size: 16px">
入库前
{{ returnStockNumber(scope.row, scope.row.number) }}
{{ scope.row.unit }}
</div>
</template>
</el-table-column> -->
<el-table-column v-if="type == 'reportinglosses'" label="上传图片">
<template v-slot="scope">
<MultiImageUpload v-model="scope.row.imgUrls" />
<el-input :value="xiaoji(scope.row)" readonly style="width: 100px" />
</template>
</el-table-column>
<!-- <el-table-column label="备注">
<template v-slot="scope">
<el-input v-model="textarea" stype="textarea" placeholder="" />
</template>
</el-table-column> -->
<el-table-column label="操作" width="80">
<template v-slot="scope">
<el-button link @click="tableData.list.splice(scope.$index, 1)">删除</el-button>
@@ -151,14 +195,21 @@
</el-table>
</div>
<div>
<el-button type="primary" :loading="queryFormLoading" @click="submitHandle">
保存并返回
</el-button>
<el-button type="primary" @click="submitHandle" :loading="queryFormLoading">确定</el-button>
</div>
<!-- 选择耗材 -->
<ConsumableList ref="ConsumableList" @success="selectConsumable" />
<el-dialog v-model="showResult" :show-close="false" :close-on-press-escape="false" :close-on-click-modal="false">
<el-result icon="success" title="入库提交成功" :subTitle="`共操作${tableData.list.length}件商品`">
<el-dialog
v-model="showResult"
:show-close="false"
:close-on-press-escape="false"
:close-on-click-modal="false"
>
<el-result
icon="success"
title="入库提交成功"
:subTitle="`共操作${tableData.list.length}件商品`"
>
<template #extra>
<template>
<el-button type="primary" size="medium" @click="resetHandle">创建新的入库单</el-button>
@@ -180,8 +231,6 @@ import vendorApi from "@/api/product/vendor";
import stockApi from "@/api/product/stock";
import dayjs from "dayjs";
import goodsList from "./components/goods-list.vue";
import MultiImageUpload from "@/components/Upload/MultiImageUpload.vue";
import ConsumableList from "./components/consumableList.vue";
import { formatDecimal } from "@/utils/tools.js";
export default {
@@ -199,7 +248,7 @@ export default {
{
label: "商品入库",
value: "goods",
type: "out",
type: "purveyor",
},
{
label: "耗材入库",
@@ -208,6 +257,22 @@ export default {
},
],
shopTypesActive: 0,
shopTypes: [
{
label: "供应商入库",
value: "purveyor",
},
{
label: "其他入库",
value: "purchase",
},
],
shopTypes2: [
{
label: "供应商入库",
value: "purveyor",
},
],
resetForm: "",
queryFormLoading: false,
queryForm: {
@@ -249,6 +314,11 @@ export default {
timeout: null,
};
},
mounted() {
this.type = this.$route.query.type || "in";
this.resetForm = { ...this.queryForm };
this.tbShopPurveyorGet();
},
computed: {
amountPayable() {
if (!this.tableData.list.length) return 0;
@@ -263,11 +333,6 @@ export default {
this.queryForm.amountPayable = newval;
},
},
mounted() {
this.type = this.$route.query.type || "in";
this.resetForm = { ...this.queryForm };
this.tbShopPurveyorGet();
},
methods: {
changeUnit(row) {
row.price = this.returnPrice(row, row.originPrice);
@@ -328,7 +393,6 @@ export default {
const price = row.price * row.stockNumber;
return price;
},
handleSelect(item) {
//选定后清空
this.autocompletename = "";
@@ -336,13 +400,12 @@ export default {
},
// 切换入库内容
tabChange(value) {
this.shopTypesActive = value == "in" ? 0 : 1;
tabChange(value, type) {
this.shopTypesActive = type == "in" ? 0 : 1;
this.inTabValue = value;
this.type = value;
this.resetHandle();
// this.$refs.shopList.reset(); //清除选项
// this.$refs.ConsumableList.reset(); //清除选项
this.$refs.shopList.reset(); //清除选项
this.$refs.ConsumableList.reset(); //清除选项
},
// 切换类型
changeTypeEnum(index) {
@@ -389,26 +452,21 @@ export default {
unitName: v.conUnit,
inOutNumber,
subTotal: this.xiaoji(v),
imgUrls: v.imgUrls,
number: v.number,
};
});
if (this.type == "in") {
await stockApi.in({ ...this.queryForm, bodyList });
} else if (this.type == "out") {
} else {
await stockApi.out({ ...this.queryForm, bodyList });
} else if (this.type == "reportinglosses") {
await stockApi.reportinglosses(bodyList);
}
this.queryFormLoading = false;
// const title = this.type == "in" ? "入库" : "出库";
const title = this.type == "in" ? "入库" : "出库";
ElMessage({
// message: title + "提交成功",
message: "提交成功",
message: title + "提交成功",
type: "success",
});
this.$router.push("/inventory/consumables");
this.showResult = true;
this.resetHandle(); //初始化
// this.showResult = true
// this.$refs.shopList.reset()//清除选项
// this.$refs.ConsumableList.reset()//清除选项
} catch (error) {
@@ -429,7 +487,6 @@ export default {
item.unit = item.defaultUnit || item.conUnit;
item.originPrice = item.price;
item.price = this.returnPrice(item, item.price);
item.imgUrls = item.imgUrls ? item.imgUrls : [];
return item;
});
this.tableData.list = [...this.tableData.list, ...arr];
@@ -439,8 +496,7 @@ export default {
resetHandle() {
this.showResult = false;
this.queryForm = { ...this.resetForm };
console.log(this.inTabs, this.inTabValue);
this.queryForm.type = this.inTabs.find((item) => item.type == this.inTabValue).type;
this.queryForm.type = this.inTabs.find((item) => item.value == this.inTabValue).type;
this.tableData.list = [];
this.$refs.queryForm.resetFields();
},
@@ -468,5 +524,6 @@ export default {
}
}
.app-container {}
</style>
.app-container {
}
</style>

View File

@@ -19,6 +19,7 @@ const modalConfig: IModalConfig = {
console.log("提交之前处理", data);
},
formItems: [
{
label: "名称",
prop: "name",
@@ -40,7 +41,7 @@ const modalConfig: IModalConfig = {
prop: "telephone",
rules: [{ required: false, message: "请输入联系人名字", trigger: "blur" }],
attrs: {
placeholder: "请输入联系人电话",
placeholder: "请输入联系人名字",
},
},
{
@@ -68,6 +69,7 @@ const modalConfig: IModalConfig = {
placeholder: "请输入排序",
},
},
],
};

View File

@@ -23,15 +23,7 @@ const contentConfig: IContentConfig = {
return Api.edit(data);
},
pk: "id",
toolbar: [
{
icon: "plus",
text: "新增",
type: "primary",
name: "add",
auth: "import",
},
],
toolbar: ["add"],
defaultToolbar: ["refresh", "filter", "search"],
cols: [
// { type: "selection", width: 50, align: "center" },
@@ -65,13 +57,13 @@ const contentConfig: IContentConfig = {
align: "center",
prop: "createTime",
},
// {
// label: "状态",
// align: "center",
// prop: "status",
// templet: 'custom',
// slotName: 'switch'
// },
{
label: "状态",
align: "center",
prop: "status",
templet: 'custom',
slotName: 'switch'
},
{
label: "操作",
@@ -79,7 +71,7 @@ const contentConfig: IContentConfig = {
fixed: "right",
width: 280,
templet: "tool",
operat: [{ text: "编辑", icon: 'edit', name: "edit"}, { text: "删除", icon: 'delete', type: 'danger', name: "delete"}],
operat: ["edit", 'delete'],
},
],
};

View File

@@ -19,6 +19,7 @@ const modalConfig: IModalConfig = {
console.log("提交之前处理", data);
},
formItems: [
{
label: "名称",
prop: "name",
@@ -40,7 +41,7 @@ const modalConfig: IModalConfig = {
prop: "telephone",
rules: [{ required: false, message: "请输入联系人名字", trigger: "blur" }],
attrs: {
placeholder: "请输入联系人电话",
placeholder: "请输入联系人名字",
},
},
{
@@ -68,6 +69,7 @@ const modalConfig: IModalConfig = {
placeholder: "请输入排序",
},
},
],
};

View File

@@ -71,7 +71,6 @@ import contentConfig from "./config/content";
import editModalConfig from "./config/edit";
import searchConfig from "./config/search";
import { returnOptionsLabel } from "./config/config";
import { isSyncStatus } from "@/utils/index";
const {
searchRef,
@@ -88,16 +87,6 @@ const {
handleFilterChange,
} = usePage();
if (isSyncStatus()) {
contentConfig.toolbar[0].hidden = true
contentConfig.cols[contentConfig.cols.length - 1].operat[0].hidden = true
contentConfig.cols[contentConfig.cols.length - 1].operat[1].hidden = true
} else {
contentConfig.toolbar[0].hidden = false
contentConfig.cols[contentConfig.cols.length - 1].operat[0].hidden = false
contentConfig.cols[contentConfig.cols.length - 1].operat[1].hidden = false
}
// 新增
async function handleAddClick() {
addModalRef.value?.setModalVisible();

View File

@@ -198,16 +198,11 @@ function handleLogin() {
loginName: userStore.userInfo.phone,
token,
}).then((checkInfo) => {
console.log("checkInfo", checkInfo);
if (checkInfo && checkInfo.userInfo) {
userStore.meituan_douyin_info = checkInfo.userInfo;
setDouyinToken(checkInfo.userInfo.token);
}
console.log("checkInfo", checkInfo.userInfo);
userStore.meituan_douyin_info = checkInfo.userInfo;
setDouyinToken(checkInfo.userInfo.token);
});
localStorage.removeItem("shopName");
let resData = await $API_login.getPermission();
localStorage.setItem("permission", JSON.stringify(resData));
localStorage.setItem("loginType", state.loginForm.loginType);
await userStore.getUserInfo();
const { path, queryParams } = parseRedirect();
console.log(path, queryParams);

View File

@@ -1,258 +0,0 @@
<template>
<div class="app_main">
<div class="card">
<headerCard icon="myzy" name="买一送一券" intro="针对营销活动买一送一设置券品。" />
<div class="tab_wrap">
<div class="row">
<el-button type="primary" @click="CouponDialogRef.show(couponType)">
添加买一送一券
</el-button>
</div>
<div class="row">
<el-table :data="tableData.list" border stripe v-loading="tableData.loading">
<el-table-column prop="id" label="ID" width="80" />
<el-table-column prop="title" label="名称" width="180" />
<el-table-column prop="validStartTime" label="有效期" width="320">
<template #default="scope">
<div v-if="scope.row.validType == 'fixed'">
领券后{{ scope.row.validDays }}天过期
</div>
<div v-else>
{{ scope.row.validStartTime }} - {{ scope.row.validEndTime }}
</div>
</template>
</el-table-column>
<el-table-column prop="getMode" label="用户领取方式" width="180">
<template #default="scope">
<div v-if="scope.row.getType == 'no'">
<el-text>用户不可自行领取</el-text>
</div>
<div class="column" v-else>
<div v-for="item in getModeFilter(scope.row.getMode)">
<el-tag :type="item.type" disable-transitions>
{{ item.label }}
</el-tag>
</div>
</div>
</template>
</el-table-column>
<el-table-column prop="giveNum" label="总发放数量" width="100">
<template #default="scope">
{{ scope.row.giveNum == -10086 ? "无限" : scope.row.giftNum }}
</template>
</el-table-column>
<el-table-column prop="giftNum" label="已领取" width="180">
<template #default="scope">
<div class="center">
<el-text>{{ scope.row.giftNum }}</el-text>
<el-text>|</el-text>
<el-link
type="primary"
@click="GetDetailDialogRef.show(scope.row)"
>
详情
</el-link>
</div>
</template>
</el-table-column>
<el-table-column prop="useNum" label="已使用" width="180" />
<el-table-column prop="leftNum" label="剩余" width="180" />
<el-table-column prop="" label="已关联功能" width="180">
<template #default="scope">
<el-link type="primary" @click="RelevanceDialogRef.show(scope.row)">
查看
</el-link>
</template>
</el-table-column>
<el-table-column prop="status" label="启用状态" width="100">
<template #default="scope">
<el-switch
v-model="scope.row.status"
:active-value="1"
:inactive-value="0"
:disabled="scope.row.syncId"
@change="statusChange($event, scope.row)"
/>
</template>
</el-table-column>
<el-table-column prop="createTime" label="创建时间" width="180" />
<el-table-column prop="actions" label="操作" align="center" width="140" fixed="right">
<template #default="scope">
<el-button
type="primary"
link
@click="CouponDialogRef.show(couponType, scope.row)"
>
编辑
</el-button>
<el-popconfirm
title="确认要删除吗?"
@confirm="deleteHandle(scope.row)"
>
<template #reference>
<el-button type="danger" link>删除</el-button>
</template>
</el-popconfirm>
</template>
</el-table-column>
</el-table>
</div>
<div class="row">
<el-pagination
v-model:current-page="tableData.page"
v-model:page-size="tableData.pageSize"
:page-sizes="[100, 200, 300, 400]"
background
layout="total, sizes, prev, pager, next, jumper"
:total="tableData.total"
@size-change="handleSizeChange"
@current-change="handleCurrentChange"
/>
</div>
</div>
</div>
<CouponDialog ref="CouponDialogRef" @success="resetPage" />
<RelevanceDialog ref="RelevanceDialogRef" name="营销中心/买一送一券" />
<GetDetailDialog ref="GetDetailDialogRef" />
</div>
</template>
<script setup>
import headerCard from "@/views/marketing_center/components/headerCard.vue";
import CouponDialog from "@/views/marketing_center/components/couponDialog.vue";
import RelevanceDialog from "@/views/marketing_center/components/relevanceDialog.vue";
import GetDetailDialog from "@/views/marketing_center/components/getDetailDialog.vue";
import { ref, reactive, onMounted } from "vue";
import { couponPage, addCoupon, delCoupon } from "@/api/coupon/index.js";
const CouponDialogRef = ref(null);
const RelevanceDialogRef = ref(null);
const GetDetailDialogRef = ref(null);
const couponType = ref(6); // 重要类型,优惠券类型
const tableData = reactive({
loading: true,
page: 1,
pageSize: 10,
total: 0,
list: [],
});
// 返回新的领取方式数组
function getModeFilter(arrStr) {
let arr = JSON.parse(arrStr);
const m = [
{
value: "home",
label: "首页-优惠券",
type: "primary",
},
{
value: "eat",
label: "点餐页-自动弹出",
type: "success",
},
{
value: "order",
label: "订单支付页面",
type: "warning",
},
];
return m.filter((item) => arr.includes(item.value));
}
// 改变状态
async function statusChange(e, row) {
try {
tableData.loading = true;
await addCoupon(row);
couponPageAjax();
} catch (err) {
console.log(err);
}
}
// 删除
async function deleteHandle(row) {
try {
tableData.loading = true;
await delCoupon({
id: row.id,
type: 0,
});
couponPageAjax();
} catch (err) {
console.log(err);
}
}
// 分页大小发生变化
function handleSizeChange(e) {
console.log("handleSizeChange===", e);
tableData.pageSize = e;
resetPage();
}
// 分页发生变化
function handleCurrentChange(e) {
console.log("handleCurrentChange===", e);
tableData.page = e;
resetPage();
}
// 重置列表请求
function resetPage() {
tableData.page = 1;
tableData.list = [];
couponPageAjax();
}
// 获取优惠券分页
async function couponPageAjax() {
try {
tableData.loading = true;
const res = await couponPage({
couponType: couponType.value,
page: tableData.page,
size: tableData.pageSize,
});
tableData.total = res.totalRow;
tableData.list = res.records;
} catch (err) {
console.log(err);
}
tableData.loading = false;
}
onMounted(() => {
couponPageAjax();
});
</script>
<style scoped lang="scss">
.app_main {
padding: 14px;
}
.card {
background-color: #fff;
padding: 14px;
.tab_wrap {
padding-top: 14px;
.row {
padding-top: 14px;
}
}
}
.center {
display: flex;
align-items: center;
gap: 10px;
}
.column {
display: flex;
flex-direction: column;
gap: 10px;
}
</style>

View File

@@ -1,904 +0,0 @@
<template>
<el-dialog v-model="dialogVisible" :title="titleOptions.title" width="80%" top="4vh">
<div class="scroll">
<el-form
ref="formRef"
:model="form"
:rules="formRules"
label-width="160px"
class="dialog-form"
>
<el-form-item label="优惠券名称" prop="title">
<el-input
v-model="form.title"
placeholder="请输入优惠券名称"
style="width: 300px"
/>
</el-form-item>
<div v-if="form.couponType == 1">
<el-form-item label="使用门槛" prop="fullAmount">
<div class="center">
<el-input
v-model="form.fullAmount"
placeholder="请输入使用门槛"
style="width: 240px"
input-style="text-align: center;"
>
<template #prepend></template>
<template #append></template>
</el-input>
<el-input
v-model="form.discountAmount"
placeholder="请输入满减金额"
style="width: 240px"
input-style="text-align: center;"
>
<template #prepend></template>
<template #append></template>
</el-input>
</div>
</el-form-item>
</div>
<div v-if="form.couponType == 2">
<el-form-item label="使用门槛" prop="fullAmount2">
<div class="center">
<el-input
v-model="form.fullAmount"
placeholder="请输入使用门槛"
style="width: 200px"
input-style="text-align: center;"
>
<template #prepend></template>
<template #append>可用</template>
</el-input>
</div>
</el-form-item>
<el-form-item label="指定门槛商品">
<el-radio-group v-model="goodsType">
<el-radio label="全部商品参与计算门槛" :value="1"></el-radio>
<el-radio label="部分商品参与计算门槛" :value="2"></el-radio>
</el-radio-group>
</el-form-item>
<el-form-item prop="goodsType" v-if="goodsType == 2">
<el-cascader
v-model="goodsTypeCascaderValue"
:options="goodsList"
:props="cascaderProps"
:show-all-levels="false"
:max-collapse-tags="3"
collapse-tags
clearable
style="width: 100%"
@change="selectFoodsConfirm"
></el-cascader>
</el-form-item>
<el-form-item label="使用规则">
<el-radio-group v-model="form.useRule">
<el-radio label="从最低价开始抵扣" value="price_asc"></el-radio>
<el-radio label="从最高价开始抵扣" value="price_desc"></el-radio>
</el-radio-group>
</el-form-item>
<el-form-item label="可抵扣商品件数" prop="discountNum">
<el-input
v-model="form.discountNum"
placeholder="请输入可抵扣商品件数"
style="width: 200px"
/>
</el-form-item>
</div>
<div v-if="form.couponType == 3">
<el-form-item label="折扣" prop="discountRate">
<el-input
v-model="form.discountRate"
placeholder="输入折扣(%"
style="width: 200px"
/>
</el-form-item>
<el-form-item label="使用门槛" prop="discountAmount">
<div class="center">
<el-input
v-model="form.discountAmount"
placeholder="请输入使用门槛"
style="width: 200px"
input-style="text-align: center;"
>
<template #prepend></template>
<template #append>可用</template>
</el-input>
</div>
</el-form-item>
<el-form-item label="可抵扣最大金额" prop="maxDiscountAmount">
<div class="center">
<el-input
v-model="form.maxDiscountAmount"
placeholder="请输入金额"
style="width: 200px"
>
<template #append>可用</template>
</el-input>
</div>
</el-form-item>
</div>
<div v-if="form.couponType == 4"></div>
<div v-if="form.couponType == 6"></div>
<div class="title">指定设置</div>
<el-form-item label="选择门店" prop="useShopType">
<el-radio-group v-model="form.useShopType">
<el-radio label="仅本店可用" value="only"></el-radio>
<template v-if="shopInfo.isHeadShop">
<el-radio label="全部门店" value="all"></el-radio>
<el-radio label="指定门店可用" value="custom"></el-radio>
</template>
</el-radio-group>
</el-form-item>
<el-form-item label="选择门店" v-if="form.useShopType == 'custom'">
<el-select
v-model="shops"
multiple
clearable
placeholder="请选择门店"
@change="shopsChange"
>
<el-option
:label="item.shopName"
:value="item.id"
v-for="item in branchList"
:key="item.id"
></el-option>
</el-select>
</el-form-item>
<div v-if="form.couponType != 2">
<el-form-item label="指定门槛商品" prop="goodsType">
<el-radio-group v-model="goodsType">
<el-radio label="全部商品参与计算门槛" :value="1"></el-radio>
<el-radio label="部分商品参与计算门槛" :value="2"></el-radio>
</el-radio-group>
</el-form-item>
<el-form-item v-if="goodsType == 2">
<el-cascader
v-model="goodsTypeCascaderValue"
:options="goodsList"
:props="cascaderProps"
:show-all-levels="false"
:max-collapse-tags="3"
collapse-tags
clearable
style="width: 100%"
@change="selectFoodsConfirm"
></el-cascader>
</el-form-item>
</div>
<el-form-item label="可使用类型" prop="useType">
<el-checkbox-group v-model="form.useType">
<el-checkbox value="dine" label="堂食" />
<el-checkbox value="pickup" label="自取" />
<el-checkbox value="deliv" label="配送" />
<el-checkbox value="express" label="快递" />
</el-checkbox-group>
</el-form-item>
<div class="title">时效设置</div>
<el-form-item label="有效期类型">
<el-radio-group v-model="form.validType">
<el-radio label="领券后有效期内可用" value="fixed"></el-radio>
<el-radio label="固定有效期范围内可用" value="custom"></el-radio>
</el-radio-group>
</el-form-item>
<el-form-item label="有效期" prop="validDays">
<el-input
v-model="form.validDays"
placeholder="请输入有效期"
style="width: 200px"
v-if="form.validType == 'fixed'"
input-style="text-align: center;"
>
<template #append></template>
</el-input>
<el-date-picker
v-model="validityScope"
type="daterange"
range-separator=""
start-placeholder="开始时间"
end-placeholder="结束时间"
v-if="form.validType == 'custom'"
@change="validityScopeChange"
/>
</el-form-item>
<el-form-item label="隔天生效" prop="daysToTakeEffect">
<el-input
v-model="form.daysToTakeEffect"
placeholder="请输入隔天生效日期"
style="width: 300px"
input-style="text-align: center;"
>
<template #prepend></template>
<template #append>天生效</template>
</el-input>
</el-form-item>
<el-form-item label="可用周期" prop="useDays">
<el-checkbox-group v-model="form.useDays">
<el-checkbox value="周一" label="周一" />
<el-checkbox value="周二" label="周二" />
<el-checkbox value="周三" label="周三" />
<el-checkbox value="周四" label="周四" />
<el-checkbox value="周五" label="周五" />
<el-checkbox value="周六" label="周六" />
<el-checkbox value="周七" label="周七" />
</el-checkbox-group>
</el-form-item>
<el-form-item label="指定时间段">
<el-radio-group v-model="form.useTimeType">
<el-radio label="领券后有效期内可用" value="all"></el-radio>
<el-radio label="固定有效期范围内可用" value="custom"></el-radio>
</el-radio-group>
</el-form-item>
<el-form-item v-if="form.useTimeType == 'custom'" prop="useTimeType">
<el-time-picker
v-model="useTimeScope"
is-range
range-separator=""
start-placeholder="开始时间"
end-placeholder="结束时间"
@change="useTimeScopeChange"
style="width: 300px"
/>
</el-form-item>
<div class="title">发放设置</div>
<el-form-item label="发放设置">
<el-radio-group v-model="form.getType">
<el-radio label="用户不可自行领取" value="no"></el-radio>
<el-radio label="用户可自行在小程序领取" value="yes"></el-radio>
</el-radio-group>
</el-form-item>
<el-form-item label="用户领取方式" v-if="form.getType == 'yes'" prop="getMode">
<el-checkbox-group v-model="form.getMode">
<el-checkbox value="home" label="首页-优惠券" />
<el-checkbox value="eat" label="点餐页-自动弹出" />
<el-checkbox value="order" label="订单支付页面" />
</el-checkbox-group>
</el-form-item>
<el-form-item label="总发放数量" prop="giveNum">
<div class="column">
<div class="center">
<el-switch v-model="infiniteGiveNum" @change="infiniteGiveNumChange" />
<span>关闭则为无限制</span>
</div>
<div v-if="infiniteGiveNum" style="margin-top: 10px">
<el-input
v-model="form.giveNum"
placeholder="请输入总发放数量"
style="width: 200px"
input-style="text-align: center;"
>
<template #append></template>
</el-input>
</div>
</div>
</el-form-item>
<div class="title">限量设置</div>
<el-form-item label="可领取用户">
<el-radio-group v-model="form.getUserType">
<el-radio label="全部用户可领" value="all"></el-radio>
<el-radio label="仅新用户可领取一张" value="new"></el-radio>
<el-radio label="仅会员可领取" value="vip"></el-radio>
</el-radio-group>
</el-form-item>
<el-form-item label="每人限领量" prop="getLimit">
<el-input
v-model="form.getLimit"
placeholder="请输入每人限领量"
style="width: 200px"
input-style="text-align: center;"
>
<template #append></template>
</el-input>
</el-form-item>
<el-form-item label="每人每日使用限量" prop="useLimit">
<div class="column">
<div class="center">
<el-switch
v-model="infiniteUseLimit"
@change="infiniteUseLimitChange"
/>
<span>关闭则为无限制</span>
</div>
<div v-if="infiniteUseLimit" style="margin-top: 10px">
<el-input
v-model="form.useLimit"
placeholder="请输入每人每日使用限量"
style="width: 255px"
input-style="text-align: center;"
>
<template #append>/每人1天</template>
</el-input>
</div>
</div>
</el-form-item>
<div class="title">其他设置</div>
<el-form-item label="与限时折扣同享">
<div class="column">
<div class="center">
<el-switch
v-model="form.discountShare"
:active-value="1"
:inactive-value="0"
/>
<span>开启后计算门槛时将会计入已折扣的商品</span>
</div>
</div>
</el-form-item>
<el-form-item label="与会员价/会员折扣同享">
<div class="column">
<div class="center">
<el-switch
v-model="form.vipPriceShare"
:active-value="1"
:inactive-value="0"
/>
<span>开启后计算门槛时将会计入已享受会员价/会员折扣的商品</span>
</div>
</div>
</el-form-item>
<el-form-item label="与其他优惠券同享" v-if="form.couponType == 2">
<div class="column">
<div class="center">
<el-switch
v-model="form.otherCouponShare"
:active-value="1"
:inactive-value="0"
/>
<span>开启后可与其他优惠券同时使用</span>
</div>
</div>
</el-form-item>
<div class="title">规则附加说明</div>
<el-form-item label-width="0">
<div class="column">
<div class="item">
<el-input
type="textarea"
:rows="4"
maxlength="250"
v-model="form.ruleDetails"
placeholder="填写内容"
></el-input>
</div>
<div class="item textarea-num">
{{ form.ruleDetails.length }}/250字内单文本
</div>
</div>
</el-form-item>
</el-form>
</div>
<template #footer>
<div class="dialog-footer" v-if="shopInfo.isHeadShop">
<el-button @click="dialogVisible = false"> </el-button>
<el-button type="primary" :loading="loading" @click="submitHandle"> </el-button>
</div>
</template>
</el-dialog>
</template>
<script setup>
import { dayjs } from "element-plus";
import { ref, reactive, onMounted } from "vue";
import { getBranchPage, getProductList, getCategoryList, addCoupon } from "@/api/coupon/index.js";
const shopInfo = ref("");
const dialogVisible = ref(false);
const titleOptions = reactive({
title: "添加优惠券",
couponTypeList: [
{
value: 1,
label: "满减券",
},
{
value: 2,
label: "商品兑换券",
},
{
value: 3,
label: "折扣券",
},
{
value: 4,
label: "第二件半价券",
},
{
value: 5,
label: "消费送券",
},
{
value: 6,
label: "买一送一券",
},
{
value: 7,
label: "固定价格券",
},
{
value: 8,
label: "免配送费券",
},
],
});
const cascaderProps = ref({
multiple: true,
emitPath: false,
value: "id",
label: "name",
});
// 选择指定商品
const goodsType = ref(1);
const goodsTypeCascaderValue = ref([]);
function selectFoodsConfirm(e) {
console.log(JSON.stringify(e));
form.value.foods = e.join(",");
}
// 选择的店铺列表
const shops = ref([]);
function shopsChange(e) {
form.value.useShops = e.join(",");
}
// 有效期时间
const validityScope = ref([]);
function validityScopeChange(e) {
form.value.validStartTime = dayjs(e[0]).format("YYYY-MM-DD 00:00:00");
form.value.validEndTime = dayjs(e[1]).format("YYYY-MM-DD 23:59:59");
}
// 可用时间
const useTimeScope = ref([]);
function useTimeScopeChange(e) {
form.value.useStartTime = dayjs(e[0]).format("HH:mm:00");
form.value.useEndTime = dayjs(e[1]).format("HH:mm:00");
}
// 是否为无限数量
const infiniteFlagNum = ref(-10086);
const infiniteGiveNum = ref(true);
function infiniteGiveNumChange(e) {
if (!e) {
form.giveNum = infiniteFlagNum.value;
}
formRef.value.validate();
}
// 是否为无限每人领取限量
const infiniteUseLimit = ref(true);
function infiniteUseLimitChange(e) {
if (!e) {
form.useLimit = infiniteFlagNum.value;
}
}
const formRef = ref(null);
const form = ref({
id: "",
shopId: "",
syncId: "",
couponType: 1, // 1-满减券2-商品兑换券3-折扣券4-第二件半价券5-消费送券6-买一送一券7-固定价格券8-免配送费券
title: "", // 券名称
fullAmount: "", // 使用门槛
discountAmount: "", // 使用门槛:减多少金额
useShopType: "only", // only-仅本店 all-所有门店custom-指定门店
useShops: "", // id字符串拼接
goodsType: 1, // 1=全部商品参与计算门槛 2=部分商品参与计算门槛
foods: "", // 指定门槛商品 id拼接
useType: ["dine"], // 可使用类型dine堂食/pickup自取/deliv配送/express快递
validType: "fixed", // 有效期类型fixed固定时间custom自定义时间
validDays: "", // 有效期(天)
validStartTime: "", // 有效期开始时间
validEndTime: "", // 有效期结束时间
daysToTakeEffect: 0, // 隔天生效
useDays: ["周一", "周二", "周三", "周四", "周五", "周六", "周七"], // 可用周期,如:'周一','周二','周三' , '周四' , '周五', '周六' , '周七'
useTimeType: "all", // 可用时间段类型all-全时段custom-指定时段
useStartTime: "", // 可用开始时间
useEndTime: "", // 可用结束时间
getType: "yes", // 发放设置:不可自行领取/no可领取/yes
getMode: ["home", "eat"], // 用户领取方式 home/首页-优惠券 eat/点餐页-自动弹出 order/订单支付页面
giveNum: "", // 总发放数量,-10086为不限量
getUserType: "all", // 可领取用户:全部/all新用户一次/new仅会员/vip
getLimit: "", // 每人领取限量,-10086为不限量
useLimit: "", // 每人每日使用限量,-10086为不限量
discountShare: 1, // 与限时折扣同享0-否1-是
vipPriceShare: 1, // 与会员价同享0-否1-是
ruleDetails: "", // 附加规则说明
status: 1, // 状态0-禁用1-启用
useNum: "", // 已使用数量
leftNum: "", // 剩余数量
discountRate: "", // 折扣%
maxDiscountAmount: "", // 可抵扣最大金额 元
useRule: "price_asc", // 使用规则price_asc-价格低到高price_desc-高到低
discountNum: "", // 抵扣数量
otherCouponShare: 1, // 与其它优惠共享0-否1-是
});
// 初始化
const resetForm = ref(null);
function reset() {
goodsType.value = 1;
goodsTypeCascaderValue.value = [];
shops.value = [];
validityScope.value = [];
useTimeScope.value = [];
infiniteGiveNum.value = true;
infiniteUseLimit.value = true;
form.value = { ...resetForm.value };
}
// 自定义校验使用门槛
const fullAmountValidate = (rule, value, callback) => {
if (form.value.fullAmount <= 0) {
callback(new Error("请输入使用门槛"));
} else if (form.value.discountAmount <= 0) {
callback(new Error("请输入满减金额"));
} else {
callback();
}
};
const fullAmountValidate2 = (rule, value, callback) => {
if (form.value.fullAmount <= 0) {
callback(new Error("请输入使用门槛"));
} else {
callback();
}
};
// 自定义校验选择门店
const useShopTypeValidate = (rule, value, callback) => {
if (form.value.useShopType == "custom" && form.value.useShops === "") {
callback(new Error("请选择门店"));
} else {
callback();
}
};
// 自定义校验使用门槛
const goodsTypeValidate = (rule, value, callback) => {
if (goodsType.value == 2 && form.value.foods === "") {
callback(new Error("请选择商品"));
} else {
callback();
}
};
// 自定义校验有效期类型
const validDaysValidate = (rule, value, callback) => {
if (form.value.validType == "fixed" && form.value.validDays === "") {
callback(new Error("请输入有效期"));
} else if (form.value.validType == "custom" && form.value.validStartTime === "") {
callback(new Error("请选择日期范围"));
} else {
callback();
}
};
// 自定义校验隔天生效
const daysToTakeEffectValidate = (rule, value, callback) => {
if (form.value.daysToTakeEffect < 0) {
callback(new Error("请输入大于等于0的值"));
} else {
callback();
}
};
// 自定义校验固定有效期范围内可用
const useTimeTypeValidate = (rule, value, callback) => {
if (form.value.daysToTakeEffect < 0) {
callback(new Error("请输入大于等于0的值"));
} else {
callback();
}
};
// 自定义校验每人限量
const giveNumValidate = (rule, value, callback) => {
if (form.value.giveNum <= 0 && infiniteGiveNum.value) {
callback(new Error("请输入总发放数量"));
} else {
callback();
}
};
// 自定义校验每人每日使用限量
const useLimitValidate = (rule, value, callback) => {
if (form.value.useLimit <= 0 && infiniteUseLimit.value) {
callback(new Error("请输入每人每日使用限量"));
} else {
callback();
}
};
const formRules = reactive({
title: [{ required: true, message: "请输入优惠券名称", trigger: "blur" }],
fullAmount: [{ required: true, validator: fullAmountValidate, trigger: "blur" }],
fullAmount2: [
{
required: true,
validator: fullAmountValidate2,
trigger: "blur",
},
],
useShopType: [
{
validator: useShopTypeValidate,
trigger: "change",
},
],
goodsType: [
{
validator: goodsTypeValidate,
trigger: "change",
},
],
discountNum: [{ required: true, message: "请输入可抵扣商品件数", trigger: "blur" }],
discountRate: [{ required: true, message: "输入折扣(%", trigger: "blur" }],
discountAmount: [{ required: true, message: "请输入使用门槛", trigger: "blur" }],
maxDiscountAmount: [{ required: true, message: "请输入金额", trigger: "blur" }],
useType: [{ required: true, message: "请选择可使用类型", trigger: "change" }],
validDays: [
{
required: true,
validator: validDaysValidate,
trigger: "change",
},
],
daysToTakeEffect: [
{
validator: daysToTakeEffectValidate,
trigger: "change",
},
],
useDays: [{ required: true, message: "请选择可用周期", trigger: "change" }],
useTimeType: [
{
validator: useTimeTypeValidate,
trigger: "change",
},
],
getMode: [{ required: true, message: "请选择用户领取方式", trigger: "change" }],
giveNum: [
{
validator: giveNumValidate,
trigger: "blur",
},
],
getLimit: [{ required: true, message: "请输入每人限领量", trigger: "blur" }],
useLimit: [
{
validator: useLimitValidate,
trigger: "blur",
},
],
});
// 开始提交
const emits = defineEmits(["success"]);
const loading = ref(false);
function submitHandle() {
formRef.value.validate(async (valid) => {
try {
if (valid) {
loading.value = true;
form.value.shopId = shopInfo.value.shopId;
await addCoupon(form.value);
emits("success");
dialogVisible.value = false;
}
} catch (err) {
console.log(err);
}
loading.value = false;
});
}
// 从本地获取商户信息
function getLocalShopInfo() {
shopInfo.value = JSON.parse(localStorage.getItem("userInfo"));
}
// 获取分店列表
const branchList = ref([]);
async function getBranchPageAjax() {
try {
const res = await getBranchPage();
branchList.value = res.records;
} catch (err) {
console.log(err);
}
}
// 获取商品列表
const goodsList = ref([]);
async function getProductListAjax() {
try {
const categorys = await getCategoryList();
const products = await getProductList();
goodsList.value = formatCategoryWithProducts(categorys, products);
} catch (err) {
console.log(err);
}
}
// 给分类组合相应的商品
function formatCategoryWithProducts(categories, products) {
// 步骤1遍历所有分类为每个分类匹配对应的商品
const allCategoriesWithProducts = categories.map((category) => {
// 匹配当前分类下的商品通过category.id === product.categoryId关联
const matchedProducts = products
.filter((product) => product.categoryId === category.id) // 关键按分类ID匹配商品
.map((product) => ({
id: product.id,
name: product.name, // 提取商品的id和name
}));
// 组装单个分类的结构
return {
id: category.id,
name: category.name,
children: matchedProducts, // 该分类下的商品(空数组表示无商品)
};
});
// 步骤2过滤掉“无商品”的分类children为空数组的分类
return allCategoriesWithProducts.filter((item) => item.children.length > 0);
}
// 显示弹窗
function show(t, obj = null) {
let m = titleOptions.couponTypeList.find((item) => item.value == t);
if (obj && obj.id) {
titleOptions.title = `编辑${m.label}`;
form.value = { ...obj };
form.value.getMode = JSON.parse(form.value.getMode);
form.value.useDays = JSON.parse(form.value.useDays);
form.value.useType = JSON.parse(form.value.useType);
if (form.value.foods != "") {
goodsType.value = 2;
goodsTypeCascaderValue.value = form.value.foods.split(",");
} else {
goodsType.value = 1;
}
if (form.value.useShops != "" && form.value.useShopType == "custom") {
shops.value = form.value.useShops.split(",");
}
if (form.value.validType == "custom") {
validityScope.value = [form.value.validStartTime, form.value.validEndTime];
}
if (form.value.useTimeType == "custom") {
useTimeScope.value = [
convertTimeToDate(form.value.useStartTime),
convertTimeToDate(form.value.useEndTime),
];
console.log(useTimeScope.value);
}
if (form.value.giveNum == infiniteFlagNum.value) {
infiniteGiveNum.value = false;
}
if (form.value.useLimit == infiniteFlagNum.value) {
infiniteUseLimit.value = false;
}
} else {
reset();
titleOptions.title = `添加${m.label}`;
}
form.value.couponType = t;
dialogVisible.value = true;
}
/**
* 将时分秒字符串转换为完整日期格式
* @param {string} timeStr - 时分秒字符串,格式需为 HH:mm:ss如 '00:53:00'
* @param {Object} options - 可选配置项
* @param {string} [options.customDate] - 自定义日期,格式为 YYYY-MM-DD默认使用当前日期
* @param {string} [options.format='YYYY-MM-DD HH:mm:ss'] - 输出的日期格式
* @returns {string|null} 转换后的日期字符串,失败时返回 null
*/
function convertTimeToDate(timeStr, options = {}) {
// 解构配置项,设置默认值
const { customDate, format = "YYYY-MM-DD HH:mm:ss" } = options;
// 1. 校验时分秒格式(必须为 HH:mm:ss允许数字1-2位
const timeRegex = /^\d{1,2}:\d{1,2}:\d{1,2}$/;
if (!timeRegex.test(timeStr)) {
console.error("时分秒格式错误,请使用 HH:mm:ss 格式(如 00:53:00");
return null;
}
// 2. 确定日期部分(自定义日期或当前日期)
let datePart;
if (customDate) {
// 校验自定义日期格式
if (!dayjs(customDate, "YYYY-MM-DD", true).isValid()) {
console.error("自定义日期格式错误,请使用 YYYY-MM-DD 格式(如 2024-05-20");
return null;
}
datePart = customDate;
} else {
// 使用当前日期格式YYYY-MM-DD
datePart = dayjs().format("YYYY-MM-DD");
}
// 3. 组合日期和时分秒,生成完整日期对象
const fullDateTime = `${datePart} ${timeStr}`;
const dateObj = dayjs(fullDateTime);
// 4. 校验完整日期是否有效(如避免 2024-02-30 这种无效日期)
if (!dateObj.isValid()) {
console.error("生成的日期无效,请检查日期或时分秒是否合理");
return null;
}
// 5. 按指定格式返回日期字符串
return dateObj.format(format);
}
defineExpose({
show,
});
onMounted(() => {
resetForm.value = { ...form.value };
getLocalShopInfo();
getBranchPageAjax();
getProductListAjax();
});
</script>
<style scoped lang="scss">
.title {
color: #000;
padding: 14px;
background-color: #f8f8f8;
margin-bottom: 14px;
font-size: 16px;
}
.column {
flex: 1;
display: flex;
flex-direction: column;
.item {
flex: 1;
}
}
.center {
display: flex;
align-items: center;
gap: 10px;
}
.scroll {
height: 76vh;
padding-bottom: 60px;
overflow-y: auto;
}
.dialog-footer {
position: relative;
&::after {
content: "";
width: 100%;
height: 60px;
position: absolute;
left: 0;
bottom: calc(100% + var(--el-dialog-padding-primary));
z-index: 9;
background: linear-gradient(to bottom, rgba(255, 255, 255, 0), rgba(255, 255, 255, 1));
}
}
.textarea-num {
color: #999;
display: flex;
justify-content: flex-end;
}
</style>

View File

@@ -1,227 +0,0 @@
<template>
<div>
<el-dialog title="已领取详情" v-model="dialogVisible" width="80%">
<div>
<el-form :model="querForm" inline>
<el-form-item label="搜索">
<el-input
v-model="querForm.search"
placeholder="用户昵称/用户ID/用户手机"
></el-input>
</el-form-item>
<el-form-item label="状态">
<el-select
v-model="querForm.status"
placeholder="请选择"
style="width: 200px"
>
<el-option
:label="item.label"
:value="item.value"
v-for="item in statusList"
:key="item.value"
></el-option>
</el-select>
</el-form-item>
<el-form-item label="领取时间">
<el-date-picker
v-model="querForm.time"
type="datetimerange"
value-format="YYYY-MM-DD HH:mm:ss"
range-separator=""
start-placeholder="开始日期"
end-placeholder="结束日期"
/>
</el-form-item>
<el-form-item label-width="0">
<el-button type="primary" @click="searchHandle">搜索</el-button>
</el-form-item>
</el-form>
</div>
<div>
<el-table :data="tableData.list" border stripe v-loading="tableData.loading">
<el-table-column label="用户ID" prop="id" width="80"></el-table-column>
<el-table-column label="用户名称" prop="name" width="200">
<template #default="scope">
<div class="user_info">
<el-avatar :size="40" :src="scope.row.headImg" />
<el-text>{{ scope.row.nickName }}</el-text>
</div>
</template>
</el-table-column>
<el-table-column label="领取时间" prop="createTime"></el-table-column>
<el-table-column label="使用时间" prop="useTime"></el-table-column>
<el-table-column label="获得来源" prop="source"></el-table-column>
<el-table-column label="状态" prop="status">
<template #default="scope">
<el-text
:type="
statusList.find((item) => item.value == scope.row.status).type
"
>
{{
statusList.find((item) => item.value == scope.row.status).label
}}
</el-text>
</template>
</el-table-column>
<el-table-column label="操作">
<template #default="scope">
<el-popconfirm
title="确认要失效吗?"
@confirm="deleteHandle(scope.row)"
>
<template #reference>
<el-button type="danger" link>失效</el-button>
</template>
</el-popconfirm>
</template>
</el-table-column>
</el-table>
</div>
<div class="row">
<el-pagination
v-model:current-page="tableData.page"
v-model:page-size="tableData.pageSize"
:page-sizes="[10, 100, 200, 300, 400]"
background
layout="total, sizes, prev, pager, next, jumper"
:total="tableData.total"
@size-change="handleSizeChange"
@current-change="handleCurrentChange"
/>
</div>
</el-dialog>
</div>
</template>
<script setup>
import { ref, reactive } from "vue";
import { couponRecord, deleteRecord } from "@/api/coupon/index.js";
const dialogVisible = ref(false);
const row = ref(null);
const statusList = ref([
{
value: 0,
label: "未使用",
type: "warning",
},
{
value: 1,
label: "已使用",
type: "success",
},
{
value: 2,
label: "已失效",
type: "info",
},
]);
const querForm = reactive({
search: "",
status: "",
time: [],
});
// 搜索
function searchHandle() {
tableData.page = 1;
tableData.pageSize = 10;
couponRecordAjax();
}
const tableData = reactive({
loading: false,
page: 1,
pageSize: 10,
total: 0,
list: [
// {
// id: 1,
// shopId: 122,
// shopUserId: 1,
// userId: 1,
// name: "满10减2/商品卷",
// sourceId: 1,
// sourceFlowId: 1,
// createTime: "20202020",
// useTime: "20202020",
// source: "购物",
// status: 0,
// headImg:
// "https://gips1.baidu.com/it/u=3920718280,2741989496&fm=3074&app=3074&f=PNG?w=2048&h=2048",
// nickName: "张三",
// },
],
});
// 分页大小发生变化
function handleSizeChange(e) {
tableData.pageSize = e;
couponRecordAjax();
}
// 分页发生变化
function handleCurrentChange(e) {
tableData.page = e;
couponRecordAjax();
}
// 已领取详情
async function couponRecordAjax() {
try {
tableData.loading = true;
const res = await couponRecord({
search: querForm.search,
status: querForm.status,
userId: "",
id: "",
shopId: row.value.shopId,
couponId: row.value.id,
name: "",
startTime: querForm.time[0] || "",
endTime: querForm.time[1] || "",
});
} catch (error) {
console.log(error);
}
tableData.loading = false;
}
// 删除用户优惠券
async function delHandle(e) {
try {
tableData.loading = true;
await deleteRecord({ id: e.id });
couponRecordAjax();
} catch (error) {
console.log(error);
}
}
function show(obj = null) {
if (obj) {
row.value = { ...obj };
dialogVisible.value = true;
couponRecordAjax();
}
}
defineExpose({
show,
});
</script>
<style scoped lang="scss">
.row {
padding-top: 14px;
}
.user_info {
display: flex;
align-items: center;
gap: 10px;
}
</style>

Some files were not shown because too many files have changed in this diff Show More