This commit is contained in:
2026-10-24 13:33:43 +08:00
parent de3fd18246
commit 7ca96ebe2d
50 changed files with 3578 additions and 382 deletions
+2 -2
View File
@@ -2,6 +2,6 @@ VITE_APP_NAME=后台管理系统
VITE_SOCKET_URL=wss://server.gxwebsoft.com
VITE_SERVER_URL=https://gxtyzx-server.websoft.top/api
VITE_API_URL=https://gxtyzx-modules.websoft.top/api
#VITE_THINK_URL=https://gxtyzx-api2.websoft.top/api
VITE_THINK_URL=https://gxtyzx-api2.websoft.top/api
VITE_THINK_URL=http://127.0.0.1:9099/api
#VITE_THINK_URL=http://127.0.0.1:9099/api
+10
View File
@@ -0,0 +1,10 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="AugmentWebviewStateStore">
<option name="stateMap">
<map>
<entry key="CHAT_STATE" value="eyJjdXJyZW50Q29udmVyc2F0aW9uSWQiOiJkNzA0N2QyNS0wZjliLTQ5ODItOTQ2NC0xMmRlNjZjY2RkMDgiLCJjb252ZXJzYXRpb25zIjp7ImZiNmQ1YmY1LWRmOWQtNDE3Yi1iNWQwLTVkMzY1NjJkYjE2MSI6eyJpZCI6ImZiNmQ1YmY1LWRmOWQtNDE3Yi1iNWQwLTVkMzY1NjJkYjE2MSIsImNyZWF0ZWRBdElzbyI6IjIwMjUtMDYtMjRUMDk6MDI6MDQuNzcyWiIsImxhc3RJbnRlcmFjdGVkQXRJc28iOiIyMDI1LTA2LTI0VDA5OjAyOjA0Ljc3MloiLCJjaGF0SGlzdG9yeSI6W10sImZlZWRiYWNrU3RhdGVzIjp7fSwidG9vbFVzZVN0YXRlcyI6e30sImRyYWZ0RXhjaGFuZ2UiOnsicmVxdWVzdF9tZXNzYWdlIjoiIiwicmljaF90ZXh0X2pzb25fcmVwciI6eyJ0eXBlIjoiZG9jIiwiY29udGVudCI6W3sidHlwZSI6InBhcmFncmFwaCJ9XX0sIm1lbnRpb25lZF9pdGVtcyI6W10sInN0YXR1cyI6ImRyYWZ0In0sInJlcXVlc3RJZHMiOltdLCJpc1Bpbm5lZCI6ZmFsc2UsImlzU2hhcmVhYmxlIjpmYWxzZSwiZXh0cmFEYXRhIjp7Imhhc0RpcnR5RWRpdHMiOmZhbHNlfSwicGVyc29uYVR5cGUiOjB9LCJkNzA0N2QyNS0wZjliLTQ5ODItOTQ2NC0xMmRlNjZjY2RkMDgiOnsiaWQiOiJkNzA0N2QyNS0wZjliLTQ5ODItOTQ2NC0xMmRlNjZjY2RkMDgiLCJjcmVhdGVkQXRJc28iOiIyMDI1LTA2LTI0VDA5OjAyOjA0Ljg5NloiLCJsYXN0SW50ZXJhY3RlZEF0SXNvIjoiMjAyNS0wNi0yNFQwOTowMjowNC44OTZaIiwiY2hhdEhpc3RvcnkiOltdLCJmZWVkYmFja1N0YXRlcyI6e30sInRvb2xVc2VTdGF0ZXMiOnt9LCJkcmFmdEV4Y2hhbmdlIjp7InJlcXVlc3RfbWVzc2FnZSI6IiIsInJpY2hfdGV4dF9qc29uX3JlcHIiOnsidHlwZSI6ImRvYyIsImNvbnRlbnQiOlt7InR5cGUiOiJwYXJhZ3JhcGgifV19LCJtZW50aW9uZWRfaXRlbXMiOltdLCJzdGF0dXMiOiJkcmFmdCJ9LCJyZXF1ZXN0SWRzIjpbXSwiaXNQaW5uZWQiOmZhbHNlLCJpc1NoYXJlYWJsZSI6ZmFsc2UsImV4dHJhRGF0YSI6eyJoYXNEaXJ0eUVkaXRzIjpmYWxzZX0sInBlcnNvbmFUeXBlIjowLCJyb290VGFza1V1aWQiOiIxMTIyMjAyMi0yNmVmLTQ4YjAtYTkzNi04ODBlYzIxNjM1NTQifX0sImFnZW50RXhlY3V0aW9uTW9kZSI6Im1hbnVhbCIsImlzUGFuZWxDb2xsYXBzZWQiOnRydWUsInNvcnRDb252ZXJzYXRpb25zQnkiOiJsYXN0TWVzc2FnZVRpbWVzdGFtcCJ9" />
</map>
</option>
</component>
</project>
+2
View File
@@ -4,11 +4,13 @@
<option name="basePath" value="$PROJECT_DIR$/src" />
<option name="generalBasePath" value="$PROJECT_DIR$" />
<option name="manifestPath" value="$PROJECT_DIR$/src/manifest.json" />
<option name="manifestStamp" value="0" />
<option name="pagesPath" value="$PROJECT_DIR$/src/pages.json" />
<option name="scanNum" value="1" />
<option name="type" value="store" />
<option name="uniapp" value="true" />
<option name="uniappCli" value="true" />
<option name="vueVersion" value="3" />
<option name="wxAppId" value="wxd38cc38c54fa7370" />
</component>
</project>
+14 -8
View File
@@ -24,19 +24,25 @@ export default {
// 无感登录
// #ifdef MP-WEIXIN
// 1. 判断openid是否存在
if(!uni.getStorageSync('openid')){
if (!uni.getStorageSync('openid')) {
uni.login({
success: (res) => {
loginByOpenId({
code: res.code
}).then((response) => {
console.log(response,'登录成功')
const openId = response.openId;
this.openId = openId;
uni.setStorageSync('uid',response.id);
uni.setStorageSync('openid',openId);
uni.setStorageSync('username',response.username);
uni.setStorageSync('avatarUrl',response.avatarUrl);
console.log(response, '登录成功')
// const openId = response.openId;
// this.openId = openId;
// uni.setStorageSync('uid',response.id);
// uni.setStorageSync('openid',openId);
// uni.setStorageSync('username',response.username);
// uni.setStorageSync('avatarUrl',response.avatarUrl);
if (response.user.uid) {
uni.setStorageSync('access_token', response.access_token)
uni.setStorageSync('user_id', response.user.userId)
uni.setStorageSync('phone', response.user.phone)
uni.setStorageSync('uid', response.user.uid)
}
});
}
});
+11
View File
@@ -120,6 +120,17 @@ export async function doInvoice(data: ThinkInvoice) {
return Promise.reject(new Error(res.data.message));
}
export async function doInvoiceByList(data: ThinkInvoice) {
const res = await request.post<ApiResult<unknown>>(
THINK_API_URL + '/think/think-invoice/doInvoiceByList',
data
);
if (res.data.code === 0) {
return res.data.message;
}
return Promise.reject(new Error(res.data.message));
}
/**
* 根据orderNo查询发票
+50
View File
@@ -0,0 +1,50 @@
import request from '@/utils/request';
import type { ApiResult, PageResult } from '@/api';
import type { BalanceChargeLog, BalanceChargeLogParam } from './model';
import { THINK_API_URL } from '@/config/setting';
/**
* 发起余额充值
*/
export async function rechargeBalance(data: BalanceChargeLog) {
const res = await request.post<ApiResult<unknown>>(
THINK_API_URL + '/shop/balance-charge-log/recharge',
data
);
if (res.data.code === 0) {
return res.data.data;
}
return Promise.reject(new Error(res.data.message));
}
/**
* 分页查询余额充值记录
*/
export async function pageBalanceChargeLog(params: BalanceChargeLogParam) {
const res = await request.get<ApiResult<PageResult<BalanceChargeLog>>>(
THINK_API_URL + '/shop/balance-charge-log/page',
{
params
}
);
if (res.data.code === 0) {
return res.data.data;
}
return Promise.reject(new Error(res.data.message));
}
/**
* 查询余额充值记录列表
*/
export async function listBalanceChargeLog(params?: BalanceChargeLogParam) {
const res = await request.get<ApiResult<BalanceChargeLog[]>>(
THINK_API_URL + '/shop/balance-charge-log',
{
params
}
);
if (res.data.code === 0 && res.data.data) {
return res.data.data;
}
return Promise.reject(new Error(res.data.message));
}
@@ -0,0 +1,37 @@
import type { PageParam } from '@/api';
/**
*
*/
export interface BalanceChargeLog {
//
id?: number;
//
amount?: string;
//
orderNo?: string;
//
isPaid?: number;
//
paidNumber?: string;
//
userId?: number;
// 商城ID
tenantId?: number;
// 创建时间
createTime?: string;
// 修改时间
updateTime?: string;
//
remark?: string;
// 交易流水号
transactionId?: string;
}
/**
* 搜索条件
*/
export interface BalanceChargeLogParam extends PageParam {
id?: number;
keywords?: string;
}
@@ -0,0 +1,45 @@
import type { PageParam } from '@/api';
/**
* 用户余额变动明细表
*/
export interface UserBalanceLog {
// 主键ID
logId?: number;
// 用户ID
userId?: number;
// 余额变动场景(0 用户充值 1用户消费 2管理员操作 3订单退款)
scene?: number;
// 变动金额
money?: string;
// 变动后余额
balance?: string;
// 管理员备注
remark?: string;
//
orderId?: number;
// 操作人ID
adminId?: number;
// 排序(数字越小越靠前)
sortNumber?: number;
// 备注
comments?: string;
// 状态, 0正常, 1冻结
status?: number;
// 是否删除, 0否, 1是
deleted?: number;
// 租户id
tenantId?: number;
// 注册时间
createTime?: string;
// 修改时间
updateTime?: string;
}
/**
* 用户余额变动明细表搜索条件
*/
export interface UserBalanceLogParam extends PageParam {
logId?: number;
keywords?: string;
}
+36 -2
View File
@@ -1,7 +1,7 @@
import request from '@/utils/request';
import type { ApiResult, PageResult } from '@/api';
import type { FileRecord, FileRecordParam } from './model';
import { FILE_SERVER, SERVER_API_URL } from '@/config/setting';
import {FILE_SERVER, SERVER_API_URL, TENANT_ID, THINK_API_URL} from '@/config/setting';
import { getCache } from '@/api/system/cache';
import md5 from "md5";
import crypto from 'crypto-js';
@@ -218,4 +218,38 @@ export async function uploadOssByPath(filePath: string) {
error: (err) => reject(err)
})
})
}
}
/**
* 上传人脸图片(返回 base64)
*/
export async function uploadFaceByPath(filePath: string): Promise<string> {
return new Promise((resolve, reject) => {
const token = uni.getStorageSync('access_token');
uni.uploadFile({
url: THINK_API_URL + '/file/upload/face',
name: 'file',
filePath,
header: {
TenantId: TENANT_ID,
...(token ? { Authorization: token } : {})
},
success: (res) => {
try {
const data =
typeof res.data === 'string' ? JSON.parse(res.data) : res.data;
if (data?.code === 0) {
return resolve(data?.data ?? data?.message ?? data?.base64 ?? '');
}
return reject(new Error(data?.message || '上传失败'));
} catch (err) {
if (typeof res.data === 'string' && res.data) {
return resolve(res.data);
}
return reject(err);
}
},
fail: (err) => reject(err)
});
});
}
+106
View File
@@ -0,0 +1,106 @@
import request from '@/utils/request';
import type { ApiResult, PageResult } from '@/api';
import type { ThinkCardBalance, ThinkCardBalanceParam } from './model';
import { MODULES_API_URL } from '@/config/setting';
/**
* 分页查询卡余额记录
*/
export async function pageThinkCardBalance(params: ThinkCardBalanceParam) {
const res = await request.get<ApiResult<PageResult<ThinkCardBalance>>>(
MODULES_API_URL + '/think/think-card-balance/page',
{
params
}
);
if (res.data.code === 0) {
return res.data.data;
}
return Promise.reject(new Error(res.data.message));
}
/**
* 查询卡余额记录列表
*/
export async function listThinkCardBalance(params?: ThinkCardBalanceParam) {
const res = await request.get<ApiResult<ThinkCardBalance[]>>(
MODULES_API_URL + '/think/think-card-balance',
{
params
}
);
if (res.data.code === 0 && res.data.data) {
return res.data.data;
}
return Promise.reject(new Error(res.data.message));
}
/**
* 添加卡余额记录
*/
export async function addThinkCardBalance(data: ThinkCardBalance) {
const res = await request.post<ApiResult<unknown>>(
MODULES_API_URL + '/think/think-card-balance',
data
);
if (res.data.code === 0) {
return res.data.message;
}
return Promise.reject(new Error(res.data.message));
}
/**
* 修改卡余额记录
*/
export async function updateThinkCardBalance(data: ThinkCardBalance) {
const res = await request.put<ApiResult<unknown>>(
MODULES_API_URL + '/think/think-card-balance',
data
);
if (res.data.code === 0) {
return res.data.message;
}
return Promise.reject(new Error(res.data.message));
}
/**
* 删除卡余额记录
*/
export async function removeThinkCardBalance(id?: number) {
const res = await request.delete<ApiResult<unknown>>(
MODULES_API_URL + '/think/think-card-balance/' + id
);
if (res.data.code === 0) {
return res.data.message;
}
return Promise.reject(new Error(res.data.message));
}
/**
* 批量删除卡余额记录
*/
export async function removeBatchThinkCardBalance(data: (number | undefined)[]) {
const res = await request.delete<ApiResult<unknown>>(
MODULES_API_URL + '/think/think-card-balance/batch',
{
data
}
);
if (res.data.code === 0) {
return res.data.message;
}
return Promise.reject(new Error(res.data.message));
}
/**
* 根据id查询卡余额记录
*/
export async function getThinkCardBalance(id: number) {
const res = await request.get<ApiResult<ThinkCardBalance>>(
MODULES_API_URL + '/think/think-card-balance/' + id
);
if (res.data.code === 0 && res.data.data) {
return res.data.data;
}
return Promise.reject(new Error(res.data.message));
}
@@ -0,0 +1,31 @@
import type { PageParam } from '@/api';
/**
* 卡余额记录
*/
export interface ThinkCardBalance {
//
id?: number;
//
cid?: number;
//
vid?: number;
//
uid?: number;
//
balance?: string;
// 每次减少金额
reduceEach?: string;
// 下单时间
createTime?: number;
//
updateTime?: number;
}
/**
* 卡余额记录搜索条件
*/
export interface ThinkCardBalanceParam extends PageParam {
id?: number;
keywords?: string;
}
+106
View File
@@ -0,0 +1,106 @@
import request from '@/utils/request';
import type { ApiResult, PageResult } from '@/api';
import type { ThinkFtpCheckBill, ThinkFtpCheckBillParam } from './model';
import { MODULES_API_URL } from '@/config/setting';
/**
* 分页查询
*/
export async function pageThinkFtpCheckBill(params: ThinkFtpCheckBillParam) {
const res = await request.get<ApiResult<PageResult<ThinkFtpCheckBill>>>(
MODULES_API_URL + '/think/think-ftp-check-bill/page',
{
params
}
);
if (res.data.code === 0) {
return res.data.data;
}
return Promise.reject(new Error(res.data.message));
}
/**
* 查询列表
*/
export async function listThinkFtpCheckBill(params?: ThinkFtpCheckBillParam) {
const res = await request.get<ApiResult<ThinkFtpCheckBill[]>>(
MODULES_API_URL + '/think/think-ftp-check-bill',
{
params
}
);
if (res.data.code === 0 && res.data.data) {
return res.data.data;
}
return Promise.reject(new Error(res.data.message));
}
/**
* 添加
*/
export async function addThinkFtpCheckBill(data: ThinkFtpCheckBill) {
const res = await request.post<ApiResult<unknown>>(
MODULES_API_URL + '/think/think-ftp-check-bill',
data
);
if (res.data.code === 0) {
return res.data.message;
}
return Promise.reject(new Error(res.data.message));
}
/**
* 修改
*/
export async function updateThinkFtpCheckBill(data: ThinkFtpCheckBill) {
const res = await request.put<ApiResult<unknown>>(
MODULES_API_URL + '/think/think-ftp-check-bill',
data
);
if (res.data.code === 0) {
return res.data.message;
}
return Promise.reject(new Error(res.data.message));
}
/**
* 删除
*/
export async function removeThinkFtpCheckBill(id?: number) {
const res = await request.delete<ApiResult<unknown>>(
MODULES_API_URL + '/think/think-ftp-check-bill/' + id
);
if (res.data.code === 0) {
return res.data.message;
}
return Promise.reject(new Error(res.data.message));
}
/**
* 批量删除
*/
export async function removeBatchThinkFtpCheckBill(data: (number | undefined)[]) {
const res = await request.delete<ApiResult<unknown>>(
MODULES_API_URL + '/think/think-ftp-check-bill/batch',
{
data
}
);
if (res.data.code === 0) {
return res.data.message;
}
return Promise.reject(new Error(res.data.message));
}
/**
* 根据id查询
*/
export async function getThinkFtpCheckBill(id: number) {
const res = await request.get<ApiResult<ThinkFtpCheckBill>>(
MODULES_API_URL + '/think/think-ftp-check-bill/' + id
);
if (res.data.code === 0 && res.data.data) {
return res.data.data;
}
return Promise.reject(new Error(res.data.message));
}
@@ -0,0 +1,53 @@
import type { PageParam } from '@/api';
/**
*
*/
export interface ThinkFtpCheckBill {
//
id?: number;
// 终端号
deviceNo?: string;
// 卡号
cardNo?: string;
//
amount?: string;
// 结算金额
settleAmount?: string;
// 手续费
feeAmount?: string;
// 实际支付金额
paidAmount?: string;
// 参考号
refNo?: string;
// 流水号
flowNo?: string;
// 卡类型
cardType?: string;
// 发卡行
postCardType?: string;
// 支付方式
payType?: string;
// 银商订单号
orderNo?: string;
//
payTime?: string;
// 租户id
tenantId?: number;
// 状态, 0已发布, 1待审核 2已驳回 3违规内容
status?: number;
// 是否删除, 0否, 1是
deleted?: number;
// 创建时间
createTime?: string;
// 修改时间
updateTime?: string;
}
/**
* 搜索条件
*/
export interface ThinkFtpCheckBillParam extends PageParam {
id?: number;
keywords?: string;
}
+14
View File
@@ -104,3 +104,17 @@ export async function getThinkGate(id: number) {
}
return Promise.reject(new Error(res.data.message));
}
/**
* 人脸检测
*/
export async function detectFace(data: { personPhoto: string }) {
const res = await request.post<ApiResult<any>>(
THINK_API_URL + '/think/gate-control/detectFace',
data
);
if (res.data.code === 0) {
return res.data.data;
}
return Promise.reject(new Error(res.data.message));
}
+10
View File
@@ -104,3 +104,13 @@ export async function getThinkInvoice(id: number) {
}
return Promise.reject(new Error(res.data.message));
}
export async function getThinkInvoiceRes(data: ThinkInvoice) {
const res = await request.post<ApiResult<ThinkInvoice>>(
THINK_API_URL + '/think/think-invoice/getRes', data
);
if (res.data.code === 0) {
return res.data.data;
}
return Promise.reject(new Error(res.data.message));
}
+10
View File
@@ -134,3 +134,13 @@ export async function thinkOrderCheckCode(data: ThinkOrder) {
}
return Promise.reject(new Error(res.data.message));
}
export async function thinkOrderSetInterval() {
const res = await request.post<ApiResult<ThinkOrder>>(
THINK_API_URL + '/think/think-order/setInterval'
);
if (res.data.code === 0) {
return res.data;
}
return Promise.reject(new Error(res.data.message));
}
+106
View File
@@ -0,0 +1,106 @@
import request from '@/utils/request';
import type { ApiResult, PageResult } from '@/api';
import type { ThinkOrderOffCheck, ThinkOrderOffCheckParam } from './model';
import { THINK_API_URL } from '@/config/setting';
/**
* 分页查询折扣审核
*/
export async function pageThinkOrderOffCheck(params: ThinkOrderOffCheckParam) {
const res = await request.get<ApiResult<PageResult<ThinkOrderOffCheck>>>(
THINK_API_URL + '/think/think-order-off-check/page',
{
params
}
);
if (res.data.code === 0) {
return res.data.data;
}
return Promise.reject(new Error(res.data.message));
}
/**
* 查询折扣审核列表
*/
export async function listThinkOrderOffCheck(params?: ThinkOrderOffCheckParam) {
const res = await request.get<ApiResult<ThinkOrderOffCheck[]>>(
THINK_API_URL + '/think/think-order-off-check',
{
params
}
);
if (res.data.code === 0 && res.data.data) {
return res.data.data;
}
return Promise.reject(new Error(res.data.message));
}
/**
* 添加折扣审核
*/
export async function addThinkOrderOffCheck(data: ThinkOrderOffCheck) {
const res = await request.post<ApiResult<unknown>>(
THINK_API_URL + '/think/think-order-off-check',
data
);
if (res.data.code === 0) {
return res.data.message;
}
return Promise.reject(new Error(res.data.message));
}
/**
* 修改折扣审核
*/
export async function updateThinkOrderOffCheck(data: ThinkOrderOffCheck) {
const res = await request.put<ApiResult<unknown>>(
THINK_API_URL + '/think/think-order-off-check',
data
);
if (res.data.code === 0) {
return res.data.message;
}
return Promise.reject(new Error(res.data.message));
}
/**
* 删除折扣审核
*/
export async function removeThinkOrderOffCheck(id?: number) {
const res = await request.delete<ApiResult<unknown>>(
THINK_API_URL + '/think/think-order-off-check/' + id
);
if (res.data.code === 0) {
return res.data.message;
}
return Promise.reject(new Error(res.data.message));
}
/**
* 批量删除折扣审核
*/
export async function removeBatchThinkOrderOffCheck(data: (number | undefined)[]) {
const res = await request.delete<ApiResult<unknown>>(
THINK_API_URL + '/think/think-order-off-check/batch',
{
data
}
);
if (res.data.code === 0) {
return res.data.message;
}
return Promise.reject(new Error(res.data.message));
}
/**
* 根据id查询折扣审核
*/
export async function getThinkOrderOffCheck(id: number) {
const res = await request.get<ApiResult<ThinkOrderOffCheck>>(
THINK_API_URL + '/think/think-order-off-check/' + id
);
if (res.data.code === 0 && res.data.data) {
return res.data.data;
}
return Promise.reject(new Error(res.data.message));
}
@@ -0,0 +1,43 @@
import type { PageParam } from '@/api';
/**
* 折扣审核
*/
export interface ThinkOrderOffCheck {
//
id?: number;
//
oid?: number;
//
userId?: number;
// 原价
originAmount?: string;
// 折扣
rate?: string;
// 折后价
offAmount?: string;
// 申请原因
reqReason?: string;
// 拒绝原因
refuseReason?: string;
// 审核人
checkUid?: number;
// 租户id
tenantId?: number;
// 状态, 0已发布, 1待审核 2已驳回 3违规内容
status?: number;
// 是否删除, 0否, 1是
deleted?: number;
// 创建时间
createTime?: string;
// 修改时间
updateTime?: string;
}
/**
* 折扣审核搜索条件
*/
export interface ThinkOrderOffCheckParam extends PageParam {
id?: number;
keywords?: string;
}
+106
View File
@@ -0,0 +1,106 @@
import request from '@/utils/request';
import type { ApiResult, PageResult } from '@/api';
import type { ThinkSmallRecharge, ThinkSmallRechargeParam } from './model';
import { THINK_API_URL } from '@/config/setting';
/**
* 分页查询
*/
export async function pageThinkSmallRecharge(params: ThinkSmallRechargeParam) {
const res = await request.get<ApiResult<PageResult<ThinkSmallRecharge>>>(
THINK_API_URL + '/think/think-small-recharge/page',
{
params
}
);
if (res.data.code === 0) {
return res.data.data;
}
return Promise.reject(new Error(res.data.message));
}
/**
* 查询列表
*/
export async function listThinkSmallRecharge(params?: ThinkSmallRechargeParam) {
const res = await request.get<ApiResult<ThinkSmallRecharge[]>>(
THINK_API_URL + '/think/think-small-recharge',
{
params
}
);
if (res.data.code === 0 && res.data.data) {
return res.data.data;
}
return Promise.reject(new Error(res.data.message));
}
/**
* 添加
*/
export async function addThinkSmallRecharge(data: ThinkSmallRecharge) {
const res = await request.post<ApiResult<unknown>>(
THINK_API_URL + '/think/think-small-recharge',
data
);
if (res.data.code === 0) {
return res.data;
}
return Promise.reject(new Error(res.data.message));
}
/**
* 修改
*/
export async function updateThinkSmallRecharge(data: ThinkSmallRecharge) {
const res = await request.put<ApiResult<unknown>>(
THINK_API_URL + '/think/think-small-recharge',
data
);
if (res.data.code === 0) {
return res.data.message;
}
return Promise.reject(new Error(res.data.message));
}
/**
* 删除
*/
export async function removeThinkSmallRecharge(id?: number) {
const res = await request.delete<ApiResult<unknown>>(
THINK_API_URL + '/think/think-small-recharge/' + id
);
if (res.data.code === 0) {
return res.data.message;
}
return Promise.reject(new Error(res.data.message));
}
/**
* 批量删除
*/
export async function removeBatchThinkSmallRecharge(data: (number | undefined)[]) {
const res = await request.delete<ApiResult<unknown>>(
THINK_API_URL + '/think/think-small-recharge/batch',
{
data
}
);
if (res.data.code === 0) {
return res.data.message;
}
return Promise.reject(new Error(res.data.message));
}
/**
* 根据id查询
*/
export async function getThinkSmallRecharge(id: number) {
const res = await request.get<ApiResult<ThinkSmallRecharge>>(
THINK_API_URL + '/think/think-small-recharge/' + id
);
if (res.data.code === 0 && res.data.data) {
return res.data.data;
}
return Promise.reject(new Error(res.data.message));
}
@@ -0,0 +1,29 @@
import type { PageParam } from '@/api';
/**
*
*/
export interface ThinkSmallRecharge {
//
id?: number;
//
cid?: number;
//
vid?: number;
//
uid?: number;
//
amount?: string;
// 下单时间
createTime?: number;
//
updateTime?: number;
}
/**
* 搜索条件
*/
export interface ThinkSmallRechargeParam extends PageParam {
id?: number;
keywords?: string;
}
+106
View File
@@ -0,0 +1,106 @@
import request from '@/utils/request';
import type { ApiResult, PageResult } from '@/api';
import type { ThinkUserInAccess, ThinkUserInAccessParam } from './model';
import { MODULES_API_URL } from '@/config/setting';
/**
* 分页查询能刷脸开闸的用户列表
*/
export async function pageThinkUserInAccess(params: ThinkUserInAccessParam) {
const res = await request.get<ApiResult<PageResult<ThinkUserInAccess>>>(
MODULES_API_URL + '/think/think-user-in-access/page',
{
params
}
);
if (res.data.code === 0) {
return res.data.data;
}
return Promise.reject(new Error(res.data.message));
}
/**
* 查询能刷脸开闸的用户列表列表
*/
export async function listThinkUserInAccess(params?: ThinkUserInAccessParam) {
const res = await request.get<ApiResult<ThinkUserInAccess[]>>(
MODULES_API_URL + '/think/think-user-in-access',
{
params
}
);
if (res.data.code === 0 && res.data.data) {
return res.data.data;
}
return Promise.reject(new Error(res.data.message));
}
/**
* 添加能刷脸开闸的用户列表
*/
export async function addThinkUserInAccess(data: ThinkUserInAccess) {
const res = await request.post<ApiResult<unknown>>(
MODULES_API_URL + '/think/think-user-in-access',
data
);
if (res.data.code === 0) {
return res.data.message;
}
return Promise.reject(new Error(res.data.message));
}
/**
* 修改能刷脸开闸的用户列表
*/
export async function updateThinkUserInAccess(data: ThinkUserInAccess) {
const res = await request.put<ApiResult<unknown>>(
MODULES_API_URL + '/think/think-user-in-access',
data
);
if (res.data.code === 0) {
return res.data.message;
}
return Promise.reject(new Error(res.data.message));
}
/**
* 删除能刷脸开闸的用户列表
*/
export async function removeThinkUserInAccess(id?: number) {
const res = await request.delete<ApiResult<unknown>>(
MODULES_API_URL + '/think/think-user-in-access/' + id
);
if (res.data.code === 0) {
return res.data.message;
}
return Promise.reject(new Error(res.data.message));
}
/**
* 批量删除能刷脸开闸的用户列表
*/
export async function removeBatchThinkUserInAccess(data: (number | undefined)[]) {
const res = await request.delete<ApiResult<unknown>>(
MODULES_API_URL + '/think/think-user-in-access/batch',
{
data
}
);
if (res.data.code === 0) {
return res.data.message;
}
return Promise.reject(new Error(res.data.message));
}
/**
* 根据id查询能刷脸开闸的用户列表
*/
export async function getThinkUserInAccess(id: number) {
const res = await request.get<ApiResult<ThinkUserInAccess>>(
MODULES_API_URL + '/think/think-user-in-access/' + id
);
if (res.data.code === 0 && res.data.data) {
return res.data.data;
}
return Promise.reject(new Error(res.data.message));
}
@@ -0,0 +1,19 @@
import type { PageParam } from '@/api';
/**
* 能刷脸开闸的用户列表
*/
export interface ThinkUserInAccess {
//
id?: number;
//
uid?: number;
}
/**
* 能刷脸开闸的用户列表搜索条件
*/
export interface ThinkUserInAccessParam extends PageParam {
id?: number;
keywords?: string;
}
+15 -1
View File
@@ -5,7 +5,7 @@ import {THINK_API_URL} from '@/config/setting';
// 微信小程序登录
export async function loginByOpenId(data: any) {
const res = await request.post<ApiResult<ThinkUsers>>(THINK_API_URL + '/think/think-users/loginByOpenId', data);
const res = await request.post<ApiResult<ThinkUsers>>('/wx-login/loginByOpenId', data);
if (res.data.code === 0) {
return res.data.data;
}
@@ -121,3 +121,17 @@ export async function getThinkUsers(id: number) {
}
return Promise.reject(new Error(res.data.message));
}
/**
* 设置人脸已上传
*/
export async function setHasFace(data: { uid: number | string; personPhoto: string }) {
const res = await request.post<ApiResult<unknown>>(
THINK_API_URL + '/think/think-users/setHasFace',
data
);
if (res.data.code === 0) {
return res.data.data ?? res.data.message;
}
return Promise.reject(new Error(res.data.message));
}
+106
View File
@@ -0,0 +1,106 @@
import request from '@/utils/request';
import type { ApiResult, PageResult } from '@/api';
import type { ThinkUsersVipBuyLog, ThinkUsersVipBuyLogParam } from './model';
import { MODULES_API_URL } from '@/config/setting';
/**
* 分页查询Vip购卡记录
*/
export async function pageThinkUsersVipBuyLog(params: ThinkUsersVipBuyLogParam) {
const res = await request.get<ApiResult<PageResult<ThinkUsersVipBuyLog>>>(
MODULES_API_URL + '/think/think-users-vip-buy-log/page',
{
params
}
);
if (res.data.code === 0) {
return res.data.data;
}
return Promise.reject(new Error(res.data.message));
}
/**
* 查询Vip购卡记录列表
*/
export async function listThinkUsersVipBuyLog(params?: ThinkUsersVipBuyLogParam) {
const res = await request.get<ApiResult<ThinkUsersVipBuyLog[]>>(
MODULES_API_URL + '/think/think-users-vip-buy-log',
{
params
}
);
if (res.data.code === 0 && res.data.data) {
return res.data.data;
}
return Promise.reject(new Error(res.data.message));
}
/**
* 添加Vip购卡记录
*/
export async function addThinkUsersVipBuyLog(data: ThinkUsersVipBuyLog) {
const res = await request.post<ApiResult<unknown>>(
MODULES_API_URL + '/think/think-users-vip-buy-log',
data
);
if (res.data.code === 0) {
return res.data.message;
}
return Promise.reject(new Error(res.data.message));
}
/**
* 修改Vip购卡记录
*/
export async function updateThinkUsersVipBuyLog(data: ThinkUsersVipBuyLog) {
const res = await request.put<ApiResult<unknown>>(
MODULES_API_URL + '/think/think-users-vip-buy-log',
data
);
if (res.data.code === 0) {
return res.data.message;
}
return Promise.reject(new Error(res.data.message));
}
/**
* 删除Vip购卡记录
*/
export async function removeThinkUsersVipBuyLog(id?: number) {
const res = await request.delete<ApiResult<unknown>>(
MODULES_API_URL + '/think/think-users-vip-buy-log/' + id
);
if (res.data.code === 0) {
return res.data.message;
}
return Promise.reject(new Error(res.data.message));
}
/**
* 批量删除Vip购卡记录
*/
export async function removeBatchThinkUsersVipBuyLog(data: (number | undefined)[]) {
const res = await request.delete<ApiResult<unknown>>(
MODULES_API_URL + '/think/think-users-vip-buy-log/batch',
{
data
}
);
if (res.data.code === 0) {
return res.data.message;
}
return Promise.reject(new Error(res.data.message));
}
/**
* 根据id查询Vip购卡记录
*/
export async function getThinkUsersVipBuyLog(id: number) {
const res = await request.get<ApiResult<ThinkUsersVipBuyLog>>(
MODULES_API_URL + '/think/think-users-vip-buy-log/' + id
);
if (res.data.code === 0 && res.data.data) {
return res.data.data;
}
return Promise.reject(new Error(res.data.message));
}
@@ -0,0 +1,39 @@
import type { PageParam } from '@/api';
/**
* Vip购卡记录
*/
export interface ThinkUsersVipBuyLog {
//
id?: number;
//
uid?: number;
//
orderNumber?: string;
//
wechetNumber?: string;
//
amount?: string;
//
payStatus?: number;
//
payTime?: string;
// 状态, 0正常, 1冻结
status?: number;
// 是否删除, 0否, 1是
deleted?: number;
// 租户id
tenantId?: number;
// 注册时间
createTime?: string;
// 修改时间
updateTime?: string;
}
/**
* Vip购卡记录搜索条件
*/
export interface ThinkUsersVipBuyLogParam extends PageParam {
id?: number;
keywords?: string;
}
+8 -8
View File
@@ -1,13 +1,13 @@
import request from '@/utils/request';
import type { ApiResult, PageResult } from '@/api';
import type { UserBalanceLog, UserBalanceLogParam } from './model';
import { MODULES_API_URL } from '../../../config/setting';
import { THINK_API_URL } from '../../../config/setting';
/**
* 分页查询余额明细
*/
export async function pageUserBalanceLog(params: UserBalanceLogParam) {
const res = await request.get<ApiResult<PageResult<UserBalanceLog>>>(MODULES_API_URL + '/shop/user-balance-log/page', { params });
const res = await request.get<ApiResult<PageResult<UserBalanceLog>>>(THINK_API_URL + '/shop/user-balance-log/page', { params });
if (res.data.code === 0) {
return res.data.data;
}
@@ -18,7 +18,7 @@ export async function pageUserBalanceLog(params: UserBalanceLogParam) {
* 查询余额明细列表
*/
export async function listUserBalanceLog(params?: UserBalanceLogParam) {
const res = await request.get<ApiResult<UserBalanceLog[]>>(MODULES_API_URL + '/shop/user-balance-log', {
const res = await request.get<ApiResult<UserBalanceLog[]>>(THINK_API_URL + '/shop/user-balance-log', {
params
});
if (res.data.code === 0 && res.data.data) {
@@ -31,7 +31,7 @@ export async function listUserBalanceLog(params?: UserBalanceLogParam) {
* 根据id查询余额明细
*/
export async function getUserBalanceLog(id: number) {
const res = await request.get<ApiResult<UserBalanceLog>>(MODULES_API_URL + '/shop/user-balance-log/' + id);
const res = await request.get<ApiResult<UserBalanceLog>>(THINK_API_URL + '/shop/user-balance-log/' + id);
if (res.data.code === 0 && res.data.data) {
return res.data.data;
}
@@ -42,7 +42,7 @@ export async function getUserBalanceLog(id: number) {
* 添加余额明细
*/
export async function addUserBalanceLog(data: UserBalanceLog) {
const res = await request.post<ApiResult<unknown>>(MODULES_API_URL + '/shop/user-balance-log', data);
const res = await request.post<ApiResult<unknown>>(THINK_API_URL + '/shop/user-balance-log', data);
if (res.data.code === 0) {
return res.data.message;
}
@@ -53,7 +53,7 @@ export async function addUserBalanceLog(data: UserBalanceLog) {
* 修改余额明细
*/
export async function updateUserBalanceLog(data: UserBalanceLog) {
const res = await request.put<ApiResult<unknown>>(MODULES_API_URL + '/shop/user-balance-log', data);
const res = await request.put<ApiResult<unknown>>(THINK_API_URL + '/shop/user-balance-log', data);
if (res.data.code === 0) {
return res.data.message;
}
@@ -64,7 +64,7 @@ export async function updateUserBalanceLog(data: UserBalanceLog) {
* 删除余额明细
*/
export async function removeUserBalanceLog(id?: number) {
const res = await request.delete<ApiResult<unknown>>(MODULES_API_URL + '/shop/user-balance-log/' + id);
const res = await request.delete<ApiResult<unknown>>(THINK_API_URL + '/shop/user-balance-log/' + id);
if (res.data.code === 0) {
return res.data.message;
}
@@ -75,7 +75,7 @@ export async function removeUserBalanceLog(id?: number) {
* 批量删除余额明细
*/
export async function removeUserBalanceLogs(data: (number | undefined)[]) {
const res = await request.delete<ApiResult<unknown>>(MODULES_API_URL + '/shop/user-balance-log/batch', {
const res = await request.delete<ApiResult<unknown>>(THINK_API_URL + '/shop/user-balance-log/batch', {
data
});
if (res.data.code === 0) {
+1
View File
@@ -8,6 +8,7 @@ export interface UserBalanceLog {
userId?: number;
scene?: number;
money?: string;
balance?: string;
describe?: string;
remark?: string;
sortNumber?: number;
+20 -25
View File
@@ -49,24 +49,6 @@
</view>
</view>
</template>
<!-- 排版样式备份 -->
<view class="period-item" style="display: none;">
<view class="period">18:00 - 20:00</view>
<view class="field-list">
<view class="field web-bg-info">
<text class="field-name">1号场地</text>
<text class="price">580元</text>
</view>
<view class="field web-bg-success active">
<text class="field-name">2号场地</text>
<text class="price">580元</text>
</view>
<view class="field web-bg-warning">
<text class="field-name">3号场地</text>
<text class="price">580元</text>
</view>
</view>
</view>
</view>
<!-- 支付按钮 -->
<uv-gap height="50"></uv-gap>
@@ -169,6 +151,7 @@ export default {
where: {},
// 时段
periodList: [],
periodListOrigin: [],
// 场地
fieldList: [],
// 选中的场地
@@ -199,9 +182,10 @@ export default {
const app = this
let totalPrice = 0;
app.selection.map(d => {
if (app.isHalf === 1) totalPrice += d.halfPrice
else totalPrice += d.price
if (app.isHalf === 1) totalPrice += parseFloat(d.halfPrice)
else totalPrice += parseFloat(d.price)
})
totalPrice = totalPrice.toFixed(2)
carStore.totalPrice = totalPrice
// console.log('totalPrice: ', totalPrice);
return totalPrice;
@@ -264,6 +248,7 @@ export default {
this.next7day = []
let day = 7
if (this.merchantId === 37) day = 1
// else if (this.merchantId === 28) day = 30
for (let i = 0; i < day; i++) {
const day = dayjs().add(i, 'day')
this.next7day.push({
@@ -293,18 +278,26 @@ export default {
const weekList = JSON.parse(item.week)
if (parseInt(this.merchantId) === 37) {
const today = dayjs().format('YYYY-MM-DD')
if ((dayjs().isBefore(dayjs(today + ' 21:00:00')) || dayjs(this.dateTime).isAfter(dayjs())) && weekList.includes(this.week)) this.periodList.push(item)
if ((dayjs().isBefore(dayjs(today + ' 21:30:00')) || dayjs(this.dateTime).isAfter(dayjs())) && weekList.includes(this.week)) this.periodList.push(item)
} else {
// console.log(this.dateTime + ' ' + item.timePeriod.split(' - ')[0])
// console.log(dayjs().isBefore(dayjs(this.dateTime + ' ' + item.timePeriod.split(' - ')[0])))
if (weekList.includes(this.week) && dayjs().isBefore(dayjs(this.dateTime + ' ' + item.timePeriod.split(' - ')[0]))) this.periodList.push(item)
}
})
const month = dayjs().format('YYYY-MM')
this.periodList.map(item => {
console.log('this.periodList', this.periodList)
// console.log(this.dateTime)
const month = dayjs(this.dateTime).format('YYYY-MM')
this.periodListOrigin = JSON.parse(JSON.stringify(this.periodList))
this.periodList.map((item, index) => {
item.price = item.priceOrigin
item.halfPrice = item.halfPriceOrigin
if (item.prices && item.prices.includes('{')) {
const dataList = JSON.parse(item.prices)[month]
console.log(JSON.parse(item.prices), month)
if (dataList) {
console.log(dayjs(this.dateTime).format('D'))
console.log(dataList[dayjs(this.dateTime).format('D') - 1])
const price = dataList[dayjs(this.dateTime).format('D') - 1]
if (price && price !== '') {
item.price = price
@@ -320,9 +313,10 @@ export default {
}
}
}
// console.log('item', item)
return item
})
console.log('this.timeListOrigin', this.timeListOrigin)
},
onDisabled() {
this.disabled = !this.disabled;
@@ -469,7 +463,8 @@ export default {
orderCode: key,
siteTimeId: siteTime.id,
dateTime: `${this.dateTime}`,
comments: `${this.dateTime}(${getWeek(week)})${item.timePeriod}`,
// comments: `${this.dateTime}(${getWeek(week)})${item.timePeriod}`,
comments: `${this.dateTime} ${item.timePeriod}`,
week
})
console.log(app.selection);
+54 -22
View File
@@ -80,6 +80,18 @@
</template>
</uv-cell>
</block>
<uv-cell
:title="balancePayTitle"
icon="https://oss.wsdns.cn/20240511/fae57a94fa0042b9bceb721421304db1.png?x-oss-process=image/resize,m_fixed,w_100,h_100/quality,Q_90"
:cellStyle="{ padding: '20rpx 10rpx', borderRadius: '8rpx', backgroundColor: 19 === form.payType ? '#f6fff1' : '', opacity: canUseBalancePay ? 1 : 0.45 }"
:border="false"
@click="onPayType(19)"
>
<template v-slot:right-icon>
<text v-if="!canUseBalancePay" class="balance-tip">余额不足</text>
<uv-icon v-else-if="19 === form.payType" size="30rpx" name="checkbox-mark"></uv-icon>
</template>
</uv-cell>
</uv-cell-group>
<view slot="actions" class="card-actions">
<view class="card-actions-item">
@@ -182,10 +194,11 @@ import {checkPayPassword} from '@/api/passport/login';
import {getWeek, getKey} from '@/utils/common';
import {useUserStore} from '@/store/modules/user';
import dayjs from "dayjs";
import {addThinkOrder} from "@/api/think/thinkOrder";
import {addThinkOrder, updateThinkOrder} from "@/api/think/thinkOrder";
import {listUserThinkCard} from "@/api/think/thinkCard";
import {listThinkUsersVip} from "@/api/think/thinkUsersVip";
import {number} from "@/uni_modules/uv-ui-tools/libs/function/test";
import md5 from 'md5'
const userStore = useUserStore();
// const carStore = useCarStore();
@@ -195,6 +208,15 @@ export default {
computed: {
dayjs() {
return dayjs
},
currentBalance() {
return Number(this.userInfo?.balance || this.userInfo?.money || 0);
},
canUseBalancePay() {
return this.currentBalance >= Number(this.payPrice || 0);
},
balancePayTitle() {
return `余额支付(当前余额¥${this.currentBalance.toFixed(2)})`;
}
},
data() {
@@ -558,6 +580,13 @@ export default {
},
// 切换支付方式
async onPayType(index) {
if (index === 19 && !this.canUseBalancePay) {
uni.showToast({
title: '当前余额不足',
icon: 'none'
});
return false;
}
// app.payType = index;
this.form.payType = index;
console.log(this.form.payType)
@@ -643,10 +672,6 @@ export default {
return false;
}
if (form.payType === 0 && !this.isPayPasswordCorrect) {
app.$refs.payPasswordForm.open('center');
return false;
}
uni.showLoading({
title: '订单提交中.'
});
@@ -663,13 +688,15 @@ export default {
}
return item
})
const postTime = dayjs().valueOf()
form.postTime = postTime
form.sign = md5(postTime + "wxd38cc38c54fa7370" + form.startTime + this.userInfo.uid)
addThinkOrder(form)
.then((data) => {
const orderInfo = data;
console.log(data)
// 调起微信支付
if (form.payType === 1) {
// #ifdef MP-WEIXIN
uni.requestPayment({
provider: orderInfo.provider, // 服务提供商
timeStamp: orderInfo.timeStamp, // 时间戳
@@ -683,34 +710,30 @@ export default {
title: '支付成功',
icon: 'success'
});
setTimeout(function () {
setTimeout(() => {
app.disabled = false;
// uni.reLaunch({
// url: '/pages/order/order',
// success: function (e) {
// var page = getCurrentPages()[0];
// if (page == undefined || page == null) return;
// page.onLoad();
// }
// });
uni.switchTab({url: '/pages/order'})
}, 1500);
},
fail: function (err) {
fail: async (err) => {
uni.showToast({
title: '取消支付',
icon: 'error'
});
await updateThinkOrder({
id: orderInfo.orderId,
orderStatus: 3
})
console.log('支付失败', err);
app.disabled = false;
uni.switchTab({
url: '/pages/order'
});
// uni.switchTab({
// url: '/pages/order/order'
// })
}
});
// #endif
}
// 使用余额支付
if (form.payType === 0) {
if (form.payType === 19) {
if (!orderInfo) {
return uni.showToast({
title: '支付失败',
@@ -724,7 +747,6 @@ export default {
});
setTimeout(function () {
app.disabled = false;
app.$refs.payPasswordForm.close();
uni.switchTab({url: '/pages/order'})
}, 1500);
}
@@ -757,6 +779,11 @@ export default {
title: res.message || '请检查您的网络.',
icon: 'none'
});
if (res.message === '未绑定人脸') {
setTimeout(() => {
uni.switchTab({url: '/pages/user'})
}, 1500)
}
});
},
selectVipCard(card) {
@@ -807,6 +834,11 @@ page {
.container {
}
.balance-tip {
font-size: 24rpx;
color: #fa3534;
}
.checkout-car {
width: 700rpx;
left: 25rpx;
+25 -17
View File
@@ -14,15 +14,18 @@
<text class="web-text-success"></text>
</template> -->
</uv-cell>
<uv-cell title="场馆地址" :label="merchant.address" :cellStyle="{padding: '10px 5px'}">
</uv-cell>
<uv-cell title="场馆位置" v-if="merchant"
:label="`距离【${merchant.name}】${merchant.distance}公里·约${merchant.duration}分钟`" isLink
:cellStyle="{padding: '10px 5px'}" @click="mapTo(merchant)">
<uv-cell title="场馆地址" :label="merchant.address" :cellStyle="{padding: '10px 5px'}" @click="mapTo(merchant)">
<template v-slot:right-icon>
<uv-icon size="50rpx" name="map-fill" color="#5ac725" style="color: #ff0000;"></uv-icon>
</template>
</uv-cell>
<!-- <uv-cell title="场馆位置" v-if="merchant"-->
<!-- :label="`距离【${merchant.name}】${merchant.distance}公里·约${merchant.duration}分钟`" isLink-->
<!-- :cellStyle="{padding: '10px 5px'}" @click="mapTo(merchant)">-->
<!-- <template v-slot:right-icon>-->
<!-- <uv-icon size="50rpx" name="map-fill" color="#5ac725" style="color: #ff0000;"></uv-icon>-->
<!-- </template>-->
<!-- </uv-cell>-->
<uv-cell title="服务前台电话" :label="merchant.tel" :border="false" :cellStyle="{padding: '10px 5px'}"
@click="callPhone(merchant.phone)">
@@ -108,6 +111,7 @@ import X2js from 'x2js';
import {getArticle, pageArticle} from "@/api/cms/article";
import coordtransform from "coordtransform";
import dayjs from "dayjs";
import {thinkOrderSetInterval} from "@/api/think/thinkOrder";
const carStore = useCarStore();
@@ -131,9 +135,9 @@ export default {
async onLoad(option) {
this.id = option.id
carStore.merchantId = option.id
const {longitude, latitude} = await getLocationAction()
this.lat = latitude
this.lng = longitude
// const {longitude, latitude} = await getLocationAction()
// this.lat = latitude
// this.lng = longitude
await this.getProtocol()
await this.reload();
},
@@ -152,13 +156,16 @@ export default {
}
},
openProtocol() {
const hour = dayjs().format('H')
if (hour < 8 || hour === 23) {
return uni.showModal({
showCancel: false,
title: '场地预定时间为:8:00-23:00。',
})
if (!this.isLogin) {
return this.$refs.login.open('bottom');
}
const hour = dayjs().format('H')
// if (parseInt(hour) < 8 || parseInt(hour) === 23) {
// return uni.showModal({
// showCancel: false,
// title: '场地预定时间为:8:00-23:00。',
// })
// }
if (this.timer) {
clearInterval(this.timer)
this.timer = null
@@ -201,7 +208,7 @@ export default {
carStore.merchantId = merchant.merchantId
carStore.merchantName = merchant.merchantName
carStore.merchantCode = merchant.merchantCode
this.getDuration()
// this.getDuration()
})
},
async getDuration() {
@@ -269,7 +276,7 @@ export default {
}
});
},
save() {
async save() {
// if (!this.disabled) {
// uni.showToast({
// title: '请先阅读并同意订票协议',
@@ -278,6 +285,7 @@ export default {
// return false
// }
if (this.timer) clearTimeout(this.timer)
await thinkOrderSetInterval()
this.$refs.protocolPopup.close()
uni.navigateTo({
url: '/package/booking/checkout?id=' + this.id
@@ -323,7 +331,7 @@ page {
.booking-tel {
position: fixed;
z-index: 1;
top: 270px;
top: 270rpx;
right: 0;
width: 80px;
height: 38px;
+61 -102
View File
@@ -5,43 +5,49 @@
inActiveColor="#808080" @clickItem="onClickItem"/>
</view>
<view class="card-list">
<block v-for="(group, groupIndex) in cardList" :key="groupIndex">
<view class="flex flex-col justify-start items-start">
<view class="group-title">{{ group.siteNames }}</view>
<view @click="openUrl(`/package/card/checkout?cardId=${item.id}`)" class="container"
v-for="(item, index) in group.cardList" :key="index">
<view class="flex justify-between items-center w-100p p-20">
<view class="flex justify-start items-center text-28 font-bold w-100p">
<view class="web-text-heading">
{{ item.name }}
<template v-if="cardList.length">
<block v-for="(group, groupIndex) in cardList" :key="groupIndex">
<view class="flex flex-col justify-start items-start">
<view class="group-title">{{ group.siteNames }}</view>
<view @click="doBuy(item.id)" class="container"
v-for="(item, index) in group.cardList" :key="index">
<view class="flex justify-between items-center w-100p p-20">
<view class="flex justify-start items-center text-28 font-bold w-100p">
<view class="web-text-heading">
{{ item.name }}
</view>
<view class="ml-10" v-if="item.type === 1">{{
item.term
}}年
</view>
<view class="ml-10" v-if="item.type === 3 || item.type === 4">{{
item.month
}}个月
</view>
<view v-if="item.type === 2" class="ml-10">
{{ item.count }}次
</view>
<view v-if="item.type === 5" class="ml-10">{{
item.discount
}}折
</view>
</view>
<view class="ml-10" v-if="item.type === 1">{{
item.term
}}年
</view>
<view class="ml-10" v-if="item.type === 3">{{
item.month
}}个月
</view>
<view v-if="item.type === 2" class="ml-10">
{{ item.count }}次
</view>
<view v-if="item.type === 4" class="ml-10">{{
item.discount
}}折
<view class="price">
<text class="web-text-price">{{ `¥${item.price}` }}</text>
</view>
</view>
<view class="price">
<text class="web-text-price">{{ `¥${item.price}` }}</text>
<view class="text-25 text-blue pt-10 mx-20" style="line-height: 35rpx" v-if="item.siteNames">
可用场馆: {{ item.siteNames }}
</view>
<view class="text-25 text-gray py-15 mx-20" style="line-height: 35rpx">
{{ item.info }}
</view>
</view>
<view class="text-25 text-gray p-20">
{{ item.info }}
</view>
</view>
</view>
</block>
<block v-if="cardList.length == 0">
</block>
</template>
<uv-empty v-else text="暂无会员卡"/>
<block v-if="loading">
<uni-card :border="false" :padding="'18px 6px'">
<uv-skeleton rows="2" avatar :loading="hideTools" :title="false"></uv-skeleton>
</uni-card>
@@ -72,6 +78,8 @@ import * as Api from '@/api/booking/card';
import {pageWechatDeposit} from '@/api/shop/wechatDeposit';
import {getWeek, getKey} from '@/utils/common';
import {listThinkVip, listThinkVipByGroup} from "@/api/think/thinkVip";
import {listThinkUsersVip} from "@/api/think/thinkUsersVip";
import dayjs from "dayjs";
export default {
components: {},
@@ -79,6 +87,7 @@ export default {
return {
isRefresh: false,
isLogin: false,
loading: true,
userId: 0,
where: {
page: 1,
@@ -109,7 +118,8 @@ export default {
styleType: 'text',
getWeek,
// 骨架屏
hideTools: true
hideTools: true,
userVipList: []
};
},
onLoad(option) {
@@ -143,48 +153,15 @@ export default {
},
methods: {
async getCardList() {
this.loading = true
this.cardList = await listThinkVipByGroup({
type: this.where.type
})
this.loading = false
this.getUserVipList()
},
reload() {
return;
const app = this;
const {where, userId} = this;
if (userId == 0) {
app.openLogin();
return;
}
// where.userId = userId;
// uni.showLoading({
// title: '数据读取中.'
// });
app.loadMore = 'loading';
Api.pageCard(where)
.then((res) => {
const list = res.list.map((d) => {
return d;
});
if (app.cardList.length < res.count) {
app.cardList = app.cardList.concat(list);
app.canReset = true;
app.loadMore = 'no-more';
} else {
app.canReset = false;
app.loadMore = 'no-more';
}
// uni.hideLoading();
app.isRefresh = false;
app.hideTools = false;
})
.catch(() => {
uni.showToast({
title: '请检查您的网络.',
icon: 'none'
});
app.isRefresh = false;
app.hideTools = false;
});
async getUserVipList() {
this.userVipList = await listThinkUsersVip()
},
onClickItem({currentIndex}) {
@@ -209,38 +186,6 @@ export default {
url
});
},
toPay(orderId) {
uni.navigateTo({
url: '/package/booking/confirm?id=' + orderId
});
},
closeOrder(item) {
uni.showModal({
title: '确定取消此订单?',
success(o) {
if (o.confirm) {
// Api.updateOrder({
// orderStatus: 2,
// orderId: item.orderId
// })
// .then((msg) => {
// uni.showToast({
// title: msg,
// icon: 'none'
// });
// item.orderStatus = 2;
// })
// .catch(() => {
// uni.showToast({
// title: '请检查您的网络.',
// icon: 'none'
// });
// uni.hideLoading();
// });
}
}
});
},
// 弹出登录提示框
async openLogin() {
this.userId = uni.getStorageSync('user_id');
@@ -248,6 +193,20 @@ export default {
this.$refs.login.open('bottom');
return false;
}
},
doBuy(id) {
const hasCard = this.userVipList.find(item => item.vid === id)
if (hasCard) {
uni.showModal({
title: '提示',
content: `您已有该会员卡(${dayjs(hasCard.expireTime * 1000).format('YYYY-MM-DD HH:mm:ss')}过期),继续购买将在该卡上叠加过期时间/次数/金额,是否继续?`,
success: (res) => {
if (res.confirm) {
this.openUrl(`/package/card/checkout?cardId=${id}`)
}
}
})
} else this.openUrl(`/package/card/checkout?cardId=${id}`)
}
}
};
+1 -1
View File
@@ -16,7 +16,7 @@
</block>
</uv-cell-group>
<view class="py-20"
v-if="!expired && info.payStatus === 1 && info.orderStatus === 2 && (hasMerchantRole || hasMerchantClerkRole || hasSuperAdminRole)">
v-if="info.payStatus === 1 && info.orderStatus === 2 && (hasMerchantRole || hasMerchantClerkRole || hasSuperAdminRole)">
<uv-button :disabled="disabled" @click="doCheck" shape="circle" :custom-style="{width: '500rpx'}"
type="primary">核销
</uv-button>
+28 -5
View File
@@ -3,8 +3,18 @@
<view class="qrcode" v-if="form.payStatus === 1 && form.orderStatus === 2">
<!-- <uv-image :src="`${IMG_URL}${form.qrcode}`" width="200" height="200"/>-->
<text class="text-25 mb-20 text-gray">{{ countDown }}秒后自动刷新</text>
<uv-qrcode size="300px" :value="form.qrcode" v-if="form.qrcode" @click="getOrder"/>
<template v-if="form.qrCodeList && form.qrCodeList.length">
<view v-for="(item, index) in form.qrCodeList" :key="index" class="mb-25">
<uv-qrcode :size="`${qrSize}rpx`" :value="item"
@click="getOrder"/>
</view>
</template>
<uv-qrcode v-else :size="`${qrSize}rpx`" :value="form.qrcode" v-if="form.qrcode" @click="getOrder"/>
<text class="web-text-secondary">核销码(每30秒刷新,点击二维码手动刷新)</text>
<view class="flex justify-between items-center w-80p mt-20">
<uv-button @click="changeSize('-')" type="error">缩小</uv-button>
<uv-button @click="changeSize('+')" type="primary">放大</uv-button>
</view>
</view>
<uni-card title="预定信息" :border="false" :is-shadow="false" :padding="0">
<view class="order-body web-cell web-cell-align-top">
@@ -39,7 +49,7 @@
<uv-cell-group :customStyle="{ backgroundColor: '#ffffff', padding: '8px 0' }" :border="false">
<uv-cell :title="`姓名`" :value="`${form.name}`" :cellStyle="{ padding: '8px' }"/>
<uv-cell :title="`手机号码`" :value="`${form.phone}`" :cellStyle="{ padding: '8px' }"/>
<!-- <uv-cell :title="`订单号`" :value="`${form.id}`" :cellStyle="{ padding: '8px' }"/>-->
<!-- <uv-cell :title="`订单号`" :value="`${form.id}`" :cellStyle="{ padding: '8px' }"/>-->
<uv-cell :title="`订单编号`" :value="`${form.orderNum}`" :cellStyle="{ padding: '8px' }"/>
<uv-cell :title="`订单状态`" :cellStyle="{ padding: '8px' }">
<template v-slot:value>
@@ -53,7 +63,8 @@
<uv-cell :title="`下单时间`" :value="`${timeFormat(form.createTime,'yyyy-mm-dd hh:MM:ss')}`"
:cellStyle="{ padding: '8px' }"/>
<uv-cell :title="`支付方式`" :value="`${payType[form.payType]}`" :cellStyle="{ padding: '8px' }"/>
<uv-cell :title="`优惠说明`" :titleStyle="{width: '200rpx'}" :value="`${form.desc ? form.desc : '无'}`" :cellStyle="{ padding: '8px' }"
<uv-cell :title="`优惠说明`" :titleStyle="{width: '200rpx'}" :value="`${form.desc ? form.desc : '无'}`"
:cellStyle="{ padding: '8px' }"
:border="false"/>
</uv-cell-group>
</view>
@@ -143,7 +154,8 @@ export default {
activeColor: '#108001',
styleType: 'text',
countDown: 30,
interval: null
interval: null,
qrSize: 500
};
},
onLoad(option) {
@@ -228,7 +240,7 @@ export default {
clearInterval(this.interval)
this.getOrder()
}
}else clearInterval(this.interval)
} else clearInterval(this.interval)
}, 1000)
},
async openPay() {
@@ -255,6 +267,17 @@ export default {
console.log('支付失败', err);
}
})
},
changeSize(dir) {
if (dir === '-') {
if (this.qrSize > 200) {
this.qrSize -= 100
}
} else {
if (this.qrSize < 700) {
this.qrSize += 100
}
}
}
},
+318
View File
@@ -0,0 +1,318 @@
<template>
<view class="page">
<view class="text-24 font-bold mt-20 text-center text-red">注:开具会员卡发票后,无法再次开具使用该卡订场的订单发票。
</view>
<uni-card :border="false" :is-shadow="false">
<uv-cell
:title="`${formData.name ? formData.name : '请填写开票信息'}`"
:label="`${userInvoice && userInvoice.isCompany === 1 ? '单位' : '个人'}`"
:cellStyle="{ padding: '5px 0' }"
:border="false"
@click="editInvoice"
>
<template v-slot:right-icon>
<uv-icon name="arrow-right"></uv-icon>
</template>
</uv-cell>
</uni-card>
<uni-card v-if="formData.name" :border="false" :is-shadow="false" :padding="20">
<uni-forms ref="form" :modelValue="formData" :rules="rules" :label-width="100" label-position="left">
<uni-forms-item label="发票类型" name="type">
<uni-data-checkbox v-model="formData.type" :localdata="type"/>
</uni-forms-item>
<uni-forms-item label="开票类型" name="invoicetype">
<uni-data-checkbox v-model="formData.invoicetype" :localdata="invoiceType"/>
</uni-forms-item>
<block v-if="userInvoice && userInvoice.isCompany === 0">
<uni-forms-item label="名称" name="name" required>
<uv-input class="input" v-model="formData.name" type="text"/>
</uni-forms-item>
<uni-forms-item label="税号/身份证号" name="code" required>
<uv-input class="input" v-model="formData.code" type="text" placeholder="税号/身份证号(必填)"/>
</uni-forms-item>
<uni-forms-item label="手机号码" name="phone" required>
<uv-input class="input" v-model="formData.phone" type="text" placeholder="手机号码"/>
</uni-forms-item>
<uni-forms-item label="电子邮箱" name="email">
<uv-input class="input" v-model="formData.email" type="text" placeholder="电子邮箱"/>
</uni-forms-item>
</block>
<block v-if="userInvoice && userInvoice.isCompany === 1">
<uni-forms-item label="名称" name="name" required>
<uv-input class="input" v-model="formData.name" type="text" placeholder="单位名称(必填)"/>
</uni-forms-item>
<uni-forms-item label="税号" name="code" required>
<uv-input class="input" v-model="formData.code" type="text" placeholder="纳税人识别号(必填)"/>
</uni-forms-item>
<uni-forms-item label="手机号码" name="phone" required>
<uv-input class="input" v-model="formData.phone" type="text" placeholder="手机号码"/>
</uni-forms-item>
<uni-forms-item label="电子邮箱" name="email" required>
<uv-input class="input" v-model="formData.email" type="text" placeholder="电子邮箱"/>
</uni-forms-item>
<uni-forms-item label="开户行" name="bankName">
<uv-input class="input" v-model="formData.bank" type="text" placeholder="开户银行名称"/>
</uni-forms-item>
<uni-forms-item label="银行账号" name="bankAccount">
<uv-input class="input" v-model="formData.account" type="text" placeholder="开户银行账号"/>
</uni-forms-item>
<uni-forms-item label="单位地址" name="address">
<uv-input class="input" v-model="formData.address" type="text" placeholder="单位地址"/>
</uni-forms-item>
<uni-forms-item label="单位电话" name="tel">
<uv-input class="input" v-model="formData.tel" type="text" placeholder="单位电话"/>
</uni-forms-item>
<uni-forms-item label="备注" name="comments">
<uv-textarea v-model="formData.comments" placeholder="请输入备注信息" auto-height></uv-textarea>
</uni-forms-item>
</block>
<uv-button
:disabled="disabled"
class="add-emergency"
:customStyle="{ background: 'linear-gradient(to right, #70b915, #008e04)', borderRadius: '30px', color: '#ffffff' }"
text="确认开票"
@click="submit"
></uv-button>
</uni-forms>
</uni-card>
</view>
</template>
<script>
import {useUserStore} from '@/store/modules/user';
import {openUrl} from '@/utils/common';
import {useTenantStore} from '@/store/modules/tenant';
import {addThinkInvoice, pageThinkInvoice, removeThinkInvoice} from "@/api/think/thinkInvoice";
import {doInvoice, doInvoiceByList, pageUserInvoice} from "@/api/booking/userInvoice";
const tenantStore = useTenantStore();
const userStore = useUserStore();
export default {
data() {
return {
orderId: 0,
list: [],
statusBarHeight: 104,
isLogin: false,
fields: {},
logo: '',
bookingUser: {},
server: [],
order: [],
// 表单数据
formData: {
incoiveNum: null,
code: null,
orderNum: null,
oid: null,
uid: null,
price: null,
name: null,
tel: null,
address: null,
bank: null,
account: null,
code: null,
phone: null,
email: '',
type: 2,
itype: null,
invoicetype: 1,
isOpen: 2,
},
// 发票类型
type: [
{
text: '电子',
value: 2
},
// {
// text: '纸质',
// value: 1
// }
],
// 开票类型
invoiceType: [
{
text: '普票',
value: 1
},
{
text: '专票',
value: 2
}
],
rules: {
// 对name字段进行必填验证
name: {
rules: [
{
required: true,
errorMessage: '请输入开票名称'
}
]
},
// 对email字段进行必填验证
email: {
rules: [
{
format: 'email',
errorMessage: '请输入正确的邮箱地址'
}
]
}
},
userInvoice: null,
disabled: false,
};
},
onLoad(e) {
this.formData.orderIdList = e.idList.split(',').map(Number)
this.formData.itype = 1
this.formData.price = e.price
},
onShow() {
this.reload();
},
methods: {
async reload(e) {
const app = this;
// 当前登录用户信息
const userInfo = await userStore.fetchUserInfo();
app.isLogin = Object.keys(userInfo).length > 0;
// 读取最后一次
pageUserInvoice({
limit: 1
}).then((res) => {
if (res.count > 0 && !app.formData.id) {
if (res.list && res.list.length > 0) {
this.userInvoice = res.list[0];
for (let key in app.formData) {
if (res.list[0][key]) {
app.formData[key] = res.list[0][key];
}
}
if (this.userInvoice.invoiceCode) this.formData.code = this.userInvoice.invoiceCode
if (this.userInvoice.bankName) this.formData.bank = this.userInvoice.bankName
if (this.userInvoice.bankAccount) this.formData.account = this.userInvoice.bankAccount
}
// app.formData.orderId = app.orderId
}
});
},
navTo(item) {
if (!this.isLogin) {
this.$refs.login.open('bottom');
return false;
}
openUrl(item);
},
// 弹出登录提示框
openLogin() {
if (!this.isLogin) {
this.$refs.login.open('bottom');
return false;
}
},
editInvoice() {
uni.navigateTo({
url: `/package/user/invoice-edit?id=${this.formData.id}`
})
},
add() {
this.$refs.addForm.open('center');
},
// 触发提交表单
submit() {
const {formData} = this
this.$refs.form
.validate()
.then(async () => {
this.disabled = true
uni.showLoading({title: '保存中'})
if (!formData.phone) {
this.disabled = false
return uni.showToast({
title: '请输入手机号',
icon: 'success'
});
}
if (!/^1[3456789]\d{9}$/.test(formData.phone)) {
this.disabled = false
return uni.showToast({
title: '请输入正确的手机号',
icon: 'success'
})
}
if (!formData.email) formData.email = ''
// const res = await addThinkInvoice(formData)
uni.hideLoading()
// if (res && res.data) {
uni.showLoading({title: '申请开票中'})
const openRes = await doInvoiceByList(formData).catch(() => {
this.disabled = false
uni.hideLoading()
})
this.disabled = false
if (openRes) {
uni.hideLoading()
uni.showToast({
title: '已申请',
icon: 'success'
});
setTimeout(() => {
uni.navigateBack()
}, 1000)
}
// }
})
.catch((err) => {
console.log('表单错误信息:', err);
});
}
}
};
</script>
<style>
page {
background-size: 100%;
background-repeat: no-repeat;
background-color: #f0f2f5;
width: 750rpx;
overflow-x: hidden;
}
</style>
<style lang="scss">
.avatar {
padding: 20px;
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
font-size: 14px;
}
.save-user-profile {
width: 700rpx;
margin: 40rpx auto;
}
.add-emergency {
width: 500rpx !important;
margin: 40rpx auto;
}
.btn-bar {
width: 700rpx;
left: 25rpx;
position: fixed;
bottom: 30rpx;
margin: auto;
clear: both;
}
</style>
+233
View File
@@ -0,0 +1,233 @@
<template>
<view class="min-height bg-gray-light">
<uv-tabs :list="tabList" :current="current" :scrollable="false" @click="changeType"></uv-tabs>
<uv-tabs v-if="siteList.length && current === 0" :list="siteList" :current="currentSite" :scrollable="false"
@click="changeSite"></uv-tabs>
<view class="order" v-if="current === 0">
<template v-if="list.length > 0">
<block v-for="(item,index) in list" :key="index">
<view class="card m-20 border pos-r" @click="changeSelect(index)"
:class="[selectedList.includes(index) ? 'selected': '']">
<view class="order-title web-cell text-25">
<view class="web-cell web-cell-content">
<text class="merchant-name">订单号: {{ item.orderNum }}</text>
</view>
</view>
<view class="order-body web-cell web-cell-align-top">
<view class="web-cell-content">
<uv-cell-group :customStyle="{backgroundColor: '#ffffff'}" :border="false">
<block v-for="(sub,subIndex) in item.thinkOrderInfos" :key="subIndex">
<uv-cell :title="`${item.siteName} - ${sub.fieldName}`" :label="`${sub.dateTime}`"
:cellStyle="{padding: '0', paddingBottom: '5px'}" :border="false"/>
</block>
</uv-cell-group>
<view class="total-price">
<view class="text-orange text-30 font-bold">实付:¥{{ item.payPrice }}</view>
</view>
</view>
</view>
</view>
</block>
<uv-gap height="140rpx"/>
<view class="footer">
<view class="p-20">
<uv-button type="primary" shape="circle" :disabled="!selectedList.length" @click="confirm">合并开票
</uv-button>
</view>
</view>
</template>
<uv-empty v-else text="暂无可开票订单"/>
</view>
<view v-else>
<template v-if="list.length > 0">
<block v-for="(item, index) in list" :key="index">
<view class="card m-20 text-25">
<view class="flex justify-between items-center">
<view class="text-main">开票金额: {{ item.price }}元</view>
<text :class="[item.isOpen === 1 ? 'text-green' : '']">{{
item.isOpen === 1 ? '已开票' : '开票中'
}}
</text>
</view>
<view class="mt-15">税号/身份证号: {{ item.code }}</view>
<view class="mt-15">名称: {{ item.name }}</view>
<view class="mt-15">手机号码: {{ item.phone }}</view>
<view class="py-15 border-top flex justify-center items-center" v-if="item.isOpen && item.url">
<view>
<uv-button type="success" shape="circle" @click="copy(item.url)" size="mini">复制PDF链接</uv-button>
</view>
<view v-if="item.xmlUrl" class="ml-15">
<uv-button type="primary" shape="circle" @click="copy(item.xmlUrl)" size="mini">复制XML链接</uv-button>
</view>
</view>
<view class="py-15 border-top flex justify-center items-center" v-if="item.isOpen === 2">
<view>
<uv-button type="success" shape="circle" @click="checkRes(item)" size="mini">查询状态</uv-button>
</view>
</view>
</view>
</block>
<uv-gap height="140rpx"/>
</template>
<uv-empty v-else text="暂无发票"/>
</view>
</view>
</template>
<script>
import {listThinkOrder} from "@/api/think/thinkOrder";
import {getThinkInvoiceRes, listThinkInvoice} from "@/api/think/thinkInvoice";
export default {
name: "multiInvoice",
data() {
return {
current: 0,
currentSite: 0,
tabList: [{name: '开票'}, {name: '我的发票'}],
siteList: [],
list: [],
originList: [],
selectedList: [],
}
},
methods: {
changeType({index}) {
this.current = index
if (index === 0) this.getOrderList()
else this.getInvoiceList()
},
changeSite({index}) {
this.currentSite = index
this.selectedList = []
this.calList()
},
async getOrderList() {
this.list = []
let list = await listThinkOrder({
isInvoice: 2,
orderStatus: 1,
payStatus: 1,
})
list = list.filter(item => {
return item.payPrice > 0 && item.createTime > 1742400000
})
this.originList = JSON.parse(JSON.stringify(list))
console.log(this.originList)
this.siteList = []
if (this.originList.length) {
this.originList.forEach(item => {
if (!this.siteList.includes(item.siteName)) this.siteList.push(item.siteName)
})
this.siteList = this.siteList.map(name => {
return {name}
})
console.log(this.siteList)
this.calList()
}
},
calList() {
this.list = this.originList.filter(item => {
return item.siteName === this.siteList[this.currentSite].name
})
console.log(this.list)
},
async getInvoiceList() {
this.list = await listThinkInvoice({group: true})
},
changeSelect(dataIndex) {
if (this.selectedList.includes(dataIndex)) {
this.selectedList = this.selectedList.filter(item => item !== dataIndex)
} else {
this.selectedList.push(dataIndex)
}
},
confirm() {
const list = this.list.filter((item, index) => this.selectedList.includes(index))
const totalPrice = list.reduce((total, item) => total + item.payPrice, 0)
const idList = list.map(item => item.id)
uni.showModal({
title: `合并开票金额:${totalPrice}元,确定要继续吗?`,
success(o) {
if (o.confirm) {
let url = `/package/order/doMultiInvoice?idList=${idList}&price=${totalPrice}`
uni.navigateTo({url})
}
}
})
},
copy(url) {
uni.setClipboardData({
data: url,
success() {
uni.showToast({
title: '复制成功',
icon: 'none'
});
}
});
},
async checkRes(item){
const res = await getThinkInvoiceRes({id: item.id})
console.log(res)
this.getInvoiceList()
}
},
onShow() {
this.selectedList = []
this.getOrderList()
},
}
</script>
<style scoped lang="scss">
.order {
.order-title {
padding: 20rpx 0;
border-bottom: 1px #eee solid;
.merchant-avatar {
margin-right: 12rpx;
}
.btn-status {
font-size: 30rpx;
display: flex;
}
}
.order-body {
padding: 16px 0;
}
}
.selected {
border-color: #3c9cff;
&::before {
content: '';
position: absolute;
right: 0;
bottom: 0;
border: 16px solid #3c9cff;
border-top-color: transparent;
border-left-color: transparent;
border-radius: 0 0 10px 0;
}
&::after {
content: '';
width: 5px;
height: 10px;
position: absolute;
right: 6px;
bottom: 7px;
border: 1px solid #fff;
border-top-color: transparent;
border-left-color: transparent;
transform: rotate(45deg);
}
}
</style>
+13
View File
@@ -0,0 +1,13 @@
<template>
<web-view :src="url"></web-view>
</template>
<script>
export default {
data() {
return {
url: 'https://fsabk.fujica.com.cn/pages/pay/paycost?parkid=614478505861189&code=051Omill2As1Bi4XgVnl2nAH6E3OmilS&state=STATE'
}
}
}
</script>
+432
View File
@@ -0,0 +1,432 @@
<template>
<view class="balance-page">
<view class="balance-card">
<text class="balance-label">当前余额</text>
<text class="balance-value">¥{{ balanceText }}</text>
<button class="charge-button" @click="openChargePopup">充值</button>
</view>
<view class="history-card">
<view class="history-header">
<text class="history-title">余额历史</text>
</view>
<block v-if="historyList.length">
<view
v-for="item in historyList"
:key="item.logId"
class="history-item"
>
<view class="history-main">
<text class="history-remark">{{ getHistoryTitle(item) }}</text>
<text class="history-time">{{ dayjs(item.createTime).format('YYYY-MM-DD HH:mm:ss') || '--' }}</text>
</view>
<view class="history-side">
<text
class="history-amount"
:class="isIncome(item) ? 'income' : 'expense'"
>
{{ isIncome(item) ? '+' : '-' }}¥{{ formatMoney(item.money) }}
</text>
<text class="history-balance">余额 ¥{{ formatMoney(item.balance) }}</text>
</view>
</view>
</block>
<uv-empty
v-else-if="!loading"
mode="list"
text="暂无余额记录"
icon="https://oss.wsdns.cn/20260507/5dbf1446663e49b3b13d637d100ab917.png"
></uv-empty>
</view>
<uni-popup ref="chargePopup" type="center">
<view class="popup-body">
<view class="popup-title">余额充值</view>
<view class="popup-label">充值金额</view>
<view class="popup-input-wrap">
<text class="popup-currency">¥</text>
<input
v-model="chargeAmount"
class="popup-input"
type="digit"
placeholder="请输入充值金额"
@input="onChargeAmountInput"
/>
</view>
<view class="quick-amounts">
<view
v-for="item in quickAmounts"
:key="item"
class="quick-amount"
:class="{ active: chargeAmount === String(item) }"
@click="selectQuickAmount(item)"
>
{{ item }}元
</view>
</view>
<view class="popup-actions">
<button class="popup-btn ghost" @click="closeChargePopup">取消</button>
<button class="popup-btn primary" :disabled="submitting" @click="submitCharge">
{{ submitting ? '处理中...' : '确认充值' }}
</button>
</view>
</view>
</uni-popup>
<uv-loading-page :loading="loading" loading-text="加载中..."></uv-loading-page>
<ws-login ref="login" :logo="logo" @done="reload"/>
</view>
</template>
<script>
import {useUserStore} from '@/store/modules/user';
import {pageUserBalanceLog} from '@/api/user/balance-log';
import {rechargeBalance} from '@/api/shop/balanceChargeLog';
import dayjs from "dayjs";
const userStore = useUserStore();
export default {
name: 'UserBalance',
data() {
return {
logo: uni.getStorageSync('app_logo'),
loading: false,
submitting: false,
balance: 0,
historyList: [],
chargeAmount: '',
quickAmounts: [10, 20, 50, 100, 200, 500]
};
},
computed: {
balanceText() {
return this.formatMoney(this.balance);
}
},
onLoad() {
this.reload();
},
methods: {
dayjs,
formatMoney(value) {
const amount = Number(value || 0);
return amount.toFixed(2);
},
isIncome(item) {
return [0, 2, 3].includes(item.scene);
},
getHistoryTitle(item) {
if (item.remark) return item.remark;
const sceneMap = {
0: '余额充值',
1: '余额消费',
2: '管理员操作',
3: '订单退款'
};
return sceneMap[item.scene] || '余额变动';
},
onChargeAmountInput(e) {
this.chargeAmount = e.detail.value;
},
selectQuickAmount(amount) {
this.chargeAmount = String(amount);
},
async reload() {
this.loading = true;
try {
const userInfo = await userStore.fetchUserInfo();
if (!userInfo || !Object.keys(userInfo).length) {
this.$refs.login.open('bottom');
this.historyList = [];
return;
}
this.balance = Number(userInfo.balance || 0);
const historyRes = await pageUserBalanceLog({
page: 1,
limit: 100,
userId: userInfo.userId
});
this.historyList = historyRes.list || [];
} catch (error) {
this.historyList = [];
uni.showToast({
title: error.message || '加载失败',
icon: 'none'
});
} finally {
this.loading = false;
}
},
openChargePopup() {
this.chargeAmount = '';
this.$refs.chargePopup.open();
},
closeChargePopup() {
this.$refs.chargePopup.close();
},
async submitCharge() {
const amount = Number(this.chargeAmount);
if (!amount || amount <= 0) {
uni.showToast({
title: '请输入正确的充值金额',
icon: 'none'
});
return;
}
this.submitting = true;
try {
const orderInfo = await rechargeBalance({
amount: amount.toFixed(2)
});
if (!orderInfo) {
throw new Error('生成订单失败');
}
uni.requestPayment({
provider: orderInfo.provider,
timeStamp: orderInfo.timeStamp,
nonceStr: orderInfo.nonceStr,
package: orderInfo.package,
signType: orderInfo.signType,
paySign: orderInfo.paySign,
success: async () => {
uni.showToast({
title: '支付成功',
icon: 'success'
});
this.closeChargePopup();
await this.reload();
},
fail: (err) => {
if (err?.errMsg && err.errMsg.includes('cancel')) {
uni.showToast({
title: '已取消支付',
icon: 'none'
});
return;
}
uni.showToast({
title: '支付失败',
icon: 'none'
});
}
});
} catch (error) {
uni.showToast({
title: error.message || '充值失败',
icon: 'none'
});
} finally {
this.submitting = false;
}
}
}
};
</script>
<style>
page {
background: #f3f5f7;
}
</style>
<style lang="scss" scoped>
.balance-page {
min-height: 100vh;
padding: 24rpx;
}
.balance-card {
padding: 40rpx 36rpx;
border-radius: 28rpx;
background: linear-gradient(135deg, #ff7a45 0%, #ff9a62 100%);
color: #ffffff;
box-shadow: 0 20rpx 40rpx rgba(255, 122, 69, 0.18);
}
.balance-label {
font-size: 26rpx;
opacity: 0.9;
}
.balance-value {
display: block;
margin-top: 20rpx;
font-size: 64rpx;
font-weight: 700;
line-height: 1;
}
.charge-button {
margin-top: 36rpx;
width: 220rpx;
height: 76rpx;
line-height: 76rpx;
border-radius: 999rpx;
border: none;
background: rgba(255, 255, 255, 0.18);
color: #ffffff;
font-size: 28rpx;
font-weight: 600;
}
.history-card {
margin-top: 24rpx;
padding: 28rpx;
border-radius: 28rpx;
background: #ffffff;
}
.history-header {
margin-bottom: 12rpx;
}
.history-title {
font-size: 32rpx;
font-weight: 600;
color: #303133;
}
.history-item {
display: flex;
justify-content: space-between;
align-items: center;
padding: 26rpx 0;
border-bottom: 1rpx solid #f0f2f5;
}
.history-item:last-child {
border-bottom: none;
}
.history-main,
.history-side {
display: flex;
flex-direction: column;
}
.history-side {
align-items: flex-end;
}
.history-remark {
font-size: 30rpx;
color: #303133;
font-weight: 500;
}
.history-time,
.history-balance {
margin-top: 10rpx;
font-size: 24rpx;
color: #909399;
}
.history-amount {
font-size: 30rpx;
font-weight: 600;
}
.history-amount.income {
color: #19be6b;
}
.history-amount.expense {
color: #fa3534;
}
.popup-body {
width: 620rpx;
padding: 36rpx 32rpx;
border-radius: 24rpx;
background: #ffffff;
}
.popup-title {
text-align: center;
font-size: 34rpx;
font-weight: 600;
color: #303133;
}
.popup-label {
margin-top: 32rpx;
margin-bottom: 18rpx;
font-size: 26rpx;
color: #606266;
}
.popup-input-wrap {
display: flex;
align-items: center;
padding: 0 24rpx;
height: 96rpx;
border-radius: 18rpx;
background: #f5f7fa;
}
.popup-currency {
margin-right: 12rpx;
font-size: 40rpx;
font-weight: 600;
color: #303133;
}
.popup-input {
flex: 1;
font-size: 38rpx;
color: #303133;
font-weight: 600;
}
.quick-amounts {
display: flex;
flex-wrap: wrap;
gap: 16rpx;
margin-top: 24rpx;
}
.quick-amount {
min-width: 120rpx;
padding: 18rpx 0;
border-radius: 16rpx;
background: #f7f8fa;
text-align: center;
font-size: 26rpx;
color: #606266;
}
.quick-amount.active {
background: #fff1eb;
color: #ff7a45;
}
.popup-actions {
display: flex;
gap: 20rpx;
margin-top: 36rpx;
}
.popup-btn {
flex: 1;
height: 84rpx;
line-height: 84rpx;
border-radius: 999rpx;
font-size: 28rpx;
border: none;
}
.popup-btn.ghost {
background: #f2f4f7;
color: #606266;
}
.popup-btn.primary {
background: linear-gradient(135deg, #ff7a45 0%, #ff9a62 100%);
color: #ffffff;
}
.popup-btn[disabled] {
opacity: 0.7;
}
</style>
+2 -2
View File
@@ -34,7 +34,7 @@
item.remainingMoney
}}
</view>
<view class="desc web-text-heading" v-if="item.type === 1 || item.type === 3"
<view class="desc web-text-heading"
style="color: #ffffff; font-size: 14px">
{{ dayjs(item.expireTime * 1000).format('YYYY-MM-DD HH:mm') }}过期
</view>
@@ -70,7 +70,7 @@
<ws-login ref="login" :logo="logo" @done="reload"/>
</view>
<view v-if="!hideTools && cardList.length == 0">
<uv-empty mode="list" icon="https://cdn.uviewui.com/uview/empty/list.png"></uv-empty>
<uv-empty mode="list" icon="https://oss.wsdns.cn/20260507/5dbf1446663e49b3b13d637d100ab917.png"></uv-empty>
</view>
</view>
</template>
+8 -1
View File
@@ -3,7 +3,13 @@
<view v-for="(item, index) in list" :key="index">
<image class="responsive-image" :src="item.imgUrls" mode="widthFix"
@click="onDown(item.pdfUrl)"></image>
<uv-button @click="onDown(item.pdfUrl)">复制发票链接</uv-button>
<view class="flex justify-center items-center m-20" v-if="item.pdfUrl">
<view class="mr-10">
<uv-button @click="onDown(item.pdfUrl)" v-if="item.pdfUrl" type="success">复制PDF链接</uv-button>
</view>
<uv-button @click="onDown(item.xmlUrl)" v-if="item.xmlUrl">复制XML链接</uv-button>
</view>
<uv-button type="primary" v-else>开票中</uv-button>
</view>
</view>
</template>
@@ -48,6 +54,7 @@ export default {
if (res && res.list && res.list.length > 0) {
const invoiceRes = await showInvoice(res.list[0].id)
this.list = JSON.parse(invoiceRes)
console.log(this.list)
}
});
},
+14 -14
View File
@@ -5,7 +5,7 @@
:title="`场地发票`"
:cellStyle="{ padding: '5px 0' }"
:border="false"
@click="switchTabTo(`/pages/order`)"
@click="navTo(`/package/order/multiInvoice`)"
icon="https://oss.wsdns.cn/20241206/eb94f79b4d9049999554e11bc355480e.png"
>
<template v-slot:right-icon>
@@ -13,19 +13,19 @@
</template>
</uv-cell>
</uni-card>
<uni-card :border="false" :is-shadow="false">
<uv-cell
:title="`租赁发票`"
:cellStyle="{ padding: '5px 0' }"
:border="false"
@click="navTo(`/package/user/invoiceRent`)"
icon="https://oss.wsdns.cn/20241206/51119131ac50427ca72272634f24e2a1.png"
>
<template v-slot:right-icon>
<uv-icon name="arrow-right"></uv-icon>
</template>
</uv-cell>
</uni-card>
<!-- <uni-card :border="false" :is-shadow="false">-->
<!-- <uv-cell-->
<!-- :title="`租赁发票`"-->
<!-- :cellStyle="{ padding: '5px 0' }"-->
<!-- :border="false"-->
<!-- @click="navTo(`/package/user/invoiceRent`)"-->
<!-- icon="https://oss.wsdns.cn/20241206/51119131ac50427ca72272634f24e2a1.png"-->
<!-- >-->
<!-- <template v-slot:right-icon>-->
<!-- <uv-icon name="arrow-right"></uv-icon>-->
<!-- </template>-->
<!-- </uv-cell>-->
<!-- </uni-card>-->
<!-- <uni-card :border="false" :is-shadow="false">-->
<!-- <uv-cell-->
<!-- :title="`商城发票`"-->
+55 -22
View File
@@ -23,24 +23,24 @@
</uni-forms-item>
<block v-if="userInvoice && userInvoice.isCompany === 0">
<uni-forms-item label="名称" name="name" required>
<uv-input class="input" disabled v-model="formData.name" type="text"/>
<uv-input class="input" v-model="formData.name" type="text"/>
</uni-forms-item>
<uni-forms-item label="税号/身份证号" name="incoiveCode" required>
<uv-input class="input" v-model="formData.incoiveCode" type="text" placeholder="税号/身份证号(必填)"/>
<uni-forms-item label="税号/身份证号" name="code" required>
<uv-input class="input" v-model="formData.code" type="text" placeholder="税号/身份证号(必填)"/>
</uni-forms-item>
<uni-forms-item label="手机号码" name="phone">
<uv-input class="input" disabled v-model="formData.phone" type="text" placeholder="手机号码"/>
<uni-forms-item label="手机号码" name="phone" required>
<uv-input class="input" v-model="formData.phone" type="text" placeholder="手机号码"/>
</uni-forms-item>
<uni-forms-item label="电子邮箱" name="email">
<uv-input class="input" disabled v-model="formData.email" type="text" placeholder="电子邮箱"/>
<uv-input class="input" v-model="formData.email" type="text" placeholder="电子邮箱"/>
</uni-forms-item>
</block>
<block v-if="userInvoice && userInvoice.isCompany === 1">
<uni-forms-item label="名称" name="name" required>
<uv-input class="input" v-model="formData.name" type="text" placeholder="单位名称(必填)"/>
</uni-forms-item>
<uni-forms-item label="税号" name="incoiveCode" required>
<uv-input class="input" v-model="formData.incoiveCode" type="text" placeholder="纳税人识别号(必填)"/>
<uni-forms-item label="税号" name="code" required>
<uv-input class="input" v-model="formData.code" type="text" placeholder="纳税人识别号(必填)"/>
</uni-forms-item>
<uni-forms-item label="手机号码" name="phone" required>
<uv-input class="input" v-model="formData.phone" type="text" placeholder="手机号码"/>
@@ -65,6 +65,7 @@
</uni-forms-item>
</block>
<uv-button
:disabled="disabled"
class="add-emergency"
:customStyle="{ background: 'linear-gradient(to right, #70b915, #008e04)', borderRadius: '30px', color: '#ffffff' }"
text="确认开票"
@@ -72,6 +73,7 @@
></uv-button>
</uni-forms>
</uni-card>
<view class="text-24 font-bold mt-20 text-center text-red">注:开具会员卡发票后,无法再次开具使用该卡订场的订单发票。</view>
</view>
</template>
@@ -102,7 +104,7 @@ export default {
// 表单数据
formData: {
incoiveNum: null,
incoiveCode: null,
incoiveCode: '91450100737617400R',
orderNum: null,
oid: null,
uid: null,
@@ -114,10 +116,11 @@ export default {
account: null,
code: null,
phone: null,
email: null,
email: '',
type: 2,
itype: null,
invoicetype: 1,
isOpen: 2,
},
// 发票类型
type: [
@@ -134,11 +137,13 @@ export default {
invoiceType: [
{
text: '普票',
value: 1
value: 1,
disabled: false
},
{
text: '专票',
value: 2
value: 2,
disabled: false
}
],
rules: {
@@ -162,6 +167,7 @@ export default {
}
},
userInvoice: null,
disabled: false,
};
},
onLoad(e) {
@@ -169,6 +175,9 @@ export default {
this.formData.orderNum = e.orderNum
this.formData.itype = e.itype
this.formData.price = e.price
if (parseInt(this.formData.itype) === 2) {
this.invoiceType[1].disabled = true
}
},
onShow() {
this.reload();
@@ -192,7 +201,7 @@ export default {
app.formData[key] = res.list[0][key];
}
}
if (this.userInvoice.invoiceCode) this.formData.incoiveCode = this.userInvoice.invoiceCode
if (this.userInvoice.invoiceCode) this.formData.code = this.userInvoice.invoiceCode
if (this.userInvoice.bankName) this.formData.bank = this.userInvoice.bankName
if (this.userInvoice.bankAccount) this.formData.account = this.userInvoice.bankAccount
}
@@ -254,23 +263,47 @@ export default {
// 触发提交表单
submit() {
const {formData} = this
this.disabled = true
this.$refs.form
.validate()
.then(async () => {
formData.code.replace(/\s/g,"")
uni.showLoading({title: '保存中'})
if (!formData.phone) {
this.disabled = false
return uni.showToast({
title: '请输入手机号',
icon: 'success'
});
}
// 手机号校验
if (!/^1[3456789]\d{9}$/.test(formData.phone)) {
this.disabled = false
return uni.showToast({
title: '请输入正确的手机号',
icon: 'success'
})
}
if (!formData.email) formData.email = ''
const res = await addThinkInvoice(formData)
uni.hideLoading()
if (res && res.data) {
uni.showLoading({title: '申请开票中'})
await doInvoice(res.data)
uni.hideLoading()
uni.showToast({
title: '开票成功',
icon: 'success'
});
setTimeout(() => {
uni.navigateBack()
}, 1000)
const openRes = await doInvoice(res.data).catch(() => {
this.disabled = true
uni.hideLoading()
})
if (openRes) {
this.disabled = true
uni.hideLoading()
uni.showToast({
title: '已申请',
icon: 'success'
});
setTimeout(() => {
uni.navigateBack()
}, 1000)
}
}
})
.catch((err) => {
+111
View File
@@ -0,0 +1,111 @@
<template>
<view class="min-height bg-gray-light">
<uv-empty v-if="!list.length"/>
<view v-else class="flex flex-col justify-center items-center w-100p">
<view class="card m-20 text-25 w-90p" v-for="(item, index) in list" :key="index">
<view class="font-bold">订单号: {{ item.thinkOrder.orderNum }}</view>
<view class="my-10">下单时间: {{
dayjs(item.thinkOrder.createTime * 1000).format('YYYY-MM-DD HH:mm:ss')
}}
</view>
<view class="my-10">下申请时间: {{ dayjs(item.createTime).format('YYYY-MM-DD HH:mm:ss') }}</view>
<view class="my-10">申请原因: {{ item.reqReason }}</view>
<view class="my-10">场馆: {{ item.thinkOrder.siteName }}</view>
<view class="my-10 flex justify-start items-center">
<text>预定信息:</text>
<view class="flex justify-center items-start flex-col ml-10">
<view class="mb-15" v-for="(booking, bookingIndex) in item.bookingList" :key="bookingIndex">{{
booking
}}
</view>
</view>
</view>
<view class="my-10 flex justify-start items-center">
<text>审核状态:</text>
<text class="ml-10" v-if="item.status === 0">待审核</text>
<text class="ml-10 text-green" v-else-if="item.status === 1">已同意</text>
<text class="ml-10 text-red" v-else-if="item.status === 2">已拒绝</text>
</view>
<view class="my-10" v-if="item.status === 2">拒绝原因: {{ item.refuseReason }}</view>
<view class="py-15 border-top flex justify-center items-center" v-if="item.status === 0">
<view class="mx-10 flex-1">
<uv-button type="success" shape="circle" @click="pass(item)">通过</uv-button>
</view>
<view class="mx-10 flex-1">
<uv-button type="error" shape="circle" @click="refuse(item)">拒绝</uv-button>
</view>
</view>
</view>
</view>
</view>
</template>
<script setup>
import {ref} from 'vue'
import {listThinkOrderOffCheck, updateThinkOrderOffCheck} from "@/api/think/thinkOrderOffCheck";
import {onLoad} from "@dcloudio/uni-app";
import dayjs from "dayjs";
import * as Api from "@/api/booking/userInvoice";
const list = ref([])
const getList = async () => {
list.value = await listThinkOrderOffCheck()
list.value = list.value.map(item => {
item.bookingList = []
item.thinkOrder.thinkOrderInfos.forEach(d => {
item.bookingList.push(`${d.fieldName}(${d.dateTime})`)
})
return item
})
}
const pass = async (item) => {
uni.showLoading({title: '加载中'})
await updateThinkOrderOffCheck({
id: item.id,
status: 1
}).catch(err => {
uni.hideLoading()
})
uni.hideLoading()
uni.showToast({
title: '操作成功',
icon: 'none'
})
await getList()
}
const refuse = async (item) => {
uni.showModal({
title: '请输入拒绝原因',
editable: true,
success: async (o) => {
if (o.confirm) {
if (!o.content) {
return uni.showToast({
title: '请输入拒绝原因',
icon: 'none'
})
}
uni.showLoading({title: '加载中'})
await updateThinkOrderOffCheck({
id: item.id,
status: 2,
refuseReason: o.content
}).catch(err => {
uni.hideLoading()
})
uni.hideLoading()
uni.showToast({
title: '操作成功',
icon: 'none'
})
await getList()
}
}
})
}
onLoad(() => {
getList()
})
</script>
+145
View File
@@ -0,0 +1,145 @@
<template>
<view class="record-page">
<view v-if="records.length" class="record-list">
<view
class="record-card"
v-for="(item, index) in records"
:key="item.id || index"
>
<view class="card-header">
<view class="flex flex-col justify-start items-start">
<text class="card-title">{{ getCardLabel(item) }}</text>
<text class="text-24 mt-15" v-if="item.card">卡号:{{ item.card.code }}</text>
<text class="text-24 mt-15" v-if="item.usersVip">卡号:{{ item.usersVip.code }}</text>
</view>
<text class="card-amount">+¥{{ item.amount }}</text>
</view>
<view class="card-footer">
<text class="card-time">{{ formatTime(item.createTime) }}</text>
<text class="card-id" v-if="item.id">单号:{{ item.orderNo }}</text>
</view>
</view>
</view>
<uv-empty
v-else-if="!loading"
mode="list"
icon="https://oss.wsdns.cn/20260507/5dbf1446663e49b3b13d637d100ab917.png"
text="暂无充值记录"
></uv-empty>
<view v-if="loading" class="load-tips">加载中...</view>
<view v-else-if="finished && records.length" class="load-tips">没有更多了</view>
</view>
</template>
<script setup>
import { ref } from 'vue';
import { onLoad, onReachBottom } from '@dcloudio/uni-app';
import dayjs from 'dayjs';
import { pageThinkSmallRecharge } from '@/api/think/thinkSmallRecharge';
const records = ref([]);
const page = ref(1);
const limit = 20;
const loading = ref(false);
const finished = ref(false);
const formatTime = (timestamp) => {
if (!timestamp) return '';
return dayjs(timestamp * 1000).format('YYYY-MM-DD HH:mm');
};
const getCardLabel = (item) => {
if (item.vid) return 'VIP卡充值';
if (item.cid) return 'IC卡充值';
return '充值';
};
const fetchRecords = async () => {
if (loading.value || finished.value) return;
loading.value = true;
try {
const res = await pageThinkSmallRecharge({
page: page.value,
limit
});
const list = (res && res.list) || [];
records.value = records.value.concat(list);
const total = res && typeof res.count === 'number' ? res.count : 0;
if (total && records.value.length >= total) {
finished.value = true;
} else if (list.length < limit) {
finished.value = true;
} else {
page.value += 1;
}
} catch (error) {
uni.showToast({
title: error.message || '获取记录失败',
icon: 'none'
});
} finally {
loading.value = false;
}
};
onLoad(() => {
fetchRecords();
});
onReachBottom(() => {
fetchRecords();
});
</script>
<style lang="scss" scoped>
.record-page {
min-height: 100vh;
padding: 20rpx;
background-color: #f5f5f5;
}
.record-card {
background-color: #fff;
border-radius: 16rpx;
padding: 24rpx 28rpx;
margin-bottom: 20rpx;
box-shadow: 0 8rpx 20rpx rgba(0, 0, 0, 0.04);
}
.card-header {
display: flex;
align-items: center;
justify-content: space-between;
margin-bottom: 12rpx;
}
.card-title {
font-size: 28rpx;
color: #333;
font-weight: 600;
}
.card-amount {
font-size: 32rpx;
color: #d81e06;
font-weight: 700;
}
.card-footer {
display: flex;
align-items: center;
justify-content: space-between;
color: #888;
font-size: 24rpx;
}
.load-tips {
text-align: center;
color: #888;
font-size: 24rpx;
padding: 16rpx 0;
}
</style>
+485
View File
@@ -0,0 +1,485 @@
<template>
<view class="recharge-page">
<view class="record-entry" @click="goRechargeRecord">
<text class="record-text">充值记录</text>
<text class="record-arrow">></text>
</view>
<view class="card-type-section">
<view class="section-title">选择卡类型</view>
<view class="card-type-tabs">
<view
class="tab-item"
:class="{ active: cardType === 'vip' }"
@click="changeCardType('vip')"
>
VIP卡
</view>
<view
class="tab-item"
:class="{ active: cardType === 'ic' }"
@click="changeCardType('ic')"
>
IC卡
</view>
</view>
</view>
<view class="search-section">
<view class="section-title">手机号搜索</view>
<view class="search-box">
<input
class="phone-input"
v-model="phone"
type="number"
maxlength="11"
placeholder="请输入手机号"
@input="onPhoneInput"
/>
<button
class="search-btn"
:disabled="!canSearch"
@click="searchCard"
>
搜索
</button>
</view>
</view>
<view class="card-list-section" v-if="cardList.length > 0">
<view class="section-title">选择卡片</view>
<view class="card-list">
<view
class="card-item"
v-for="(item, index) in cardList"
:key="index"
:class="{ selected: selectedCard && selectedCard.id === item.id }"
@click="selectCard(item)"
>
<view class="card-name">{{ item.name || item.cardNo }}</view>
<view class="card-info" v-if="cardType === 'vip'">
<text>有效期至: {{ formatTime(item.expireTime) }}</text>
</view>
<view class="card-info" v-if="cardType === 'ic'">
<text>卡号: {{ item.cardNo }}</text>
</view>
<view class="card-balance" v-if="item.remainingMoney !== undefined">
余额: ¥{{ item.remainingMoney }}
</view>
</view>
</view>
</view>
<view class="amount-section" v-if="selectedCard">
<view class="section-title">充值金额</view>
<view class="amount-input-box">
<text class="currency">¥</text>
<input
class="amount-input"
v-model="amount"
type="digit"
placeholder="请输入充值金额"
@input="onAmountInput"
/>
</view>
<view class="quick-amount">
<view
class="amount-btn"
v-for="(item, index) in quickAmounts"
:key="index"
@click="selectQuickAmount(item)"
>
{{ item }}元
</view>
</view>
</view>
<view class="submit-section" v-if="selectedCard && amount">
<button class="submit-btn" @click="submitRecharge">
确认充值
</button>
</view>
<uv-loading-page :loading="loading" loading-text="加载中..."></uv-loading-page>
</view>
</template>
<script>
import {listThinkCard} from '@/api/think/thinkCard';
import {listThinkUsersVip} from '@/api/think/thinkUsersVip';
import dayjs from 'dayjs';
import {addThinkSmallRecharge} from "@/api/think/thinkSmallRecharge";
export default {
data() {
return {
cardType: 'vip', // vip 或 ic
phone: '',
cardList: [],
selectedCard: null,
amount: '',
quickAmounts: [10, 20, 30, 50, 100],
loading: false
};
},
computed: {
canSearch() {
return this.phone.length === 11;
}
},
methods: {
goRechargeRecord() {
uni.navigateTo({
url: '/package/user/recharge-record'
});
},
changeCardType(type) {
this.cardType = type;
this.cardList = [];
this.selectedCard = null;
this.amount = '';
},
onPhoneInput(e) {
this.phone = e.detail.value;
},
async searchCard() {
if (!this.canSearch) {
uni.showToast({
title: '请输入正确的手机号',
icon: 'none'
});
return;
}
this.loading = true;
try {
if (this.cardType === 'vip') {
this.cardList = await listThinkUsersVip({keywords: this.phone, forAdmin: true});
} else {
this.cardList = await listThinkCard({phone: this.phone, forAdmin: true});
}
if (this.cardList.length === 0) {
uni.showToast({
title: '未找到相关卡片',
icon: 'none'
});
}
} catch (error) {
uni.showToast({
title: error.message || '搜索失败',
icon: 'none'
});
} finally {
this.loading = false;
}
},
selectCard(card) {
this.selectedCard = card;
},
onAmountInput(e) {
this.amount = e.detail.value;
},
selectQuickAmount(amount) {
this.amount = amount.toString();
},
formatTime(timestamp) {
if (!timestamp) return '';
return dayjs(timestamp * 1000).format('YYYY-MM-DD');
},
submitRecharge() {
console.log(this.selectedCard)
if (!this.selectedCard) {
uni.showToast({
title: '请选择卡片',
icon: 'none'
});
return;
}
if (!this.amount || parseFloat(this.amount) <= 0) {
uni.showToast({
title: '请输入正确的充值金额',
icon: 'none'
});
return;
}
if (parseFloat(this.amount) > 100) {
uni.showToast({
title: '充值金额不能大于100元',
icon: 'none'
});
return;
}
uni.showModal({
title: '确认充值',
content: `确认为${this.cardType === 'vip' ? 'VIP卡' : 'IC卡'}充值 ¥${this.amount} 元?`,
success: async (res) => {
if (res.confirm) {
const data = {
amount: this.amount
}
if (this.cardType === 'vip') {
data.vid = this.selectedCard.id;
} else {
data.cid = this.selectedCard.id;
}
const res = await addThinkSmallRecharge(data).catch(err => {
uni.showToast({
title: err.message,
icon: 'none'
});
})
if (!res) return
const orderInfo = res.data
uni.requestPayment({
provider: orderInfo.provider, // 服务提供商
timeStamp: orderInfo.timeStamp, // 时间戳
nonceStr: orderInfo.nonceStr, // 随机字符串
package: orderInfo.package,
signType: orderInfo.signType, // 签名算法
paySign: orderInfo.paySign, // 签名
success: function (res) {
uni.showToast({
title: '支付成功',
icon: 'success'
});
this.cardList = [];
this.selectedCard = null;
this.amount = '';
},
fail: function (err) {
console.log('支付失败', err);
}
})
}
}
});
}
}
};
</script>
<style lang="scss" scoped>
.recharge-page {
min-height: 100vh;
background-color: #f5f5f5;
padding: 20rpx;
}
.section-title {
font-size: 32rpx;
font-weight: 600;
color: #333;
margin-bottom: 20rpx;
}
.card-type-section {
background: #fff;
border-radius: 16rpx;
padding: 30rpx;
margin-bottom: 20rpx;
}
.record-entry {
display: flex;
justify-content: space-between;
align-items: center;
background: #fff;
border-radius: 16rpx;
padding: 24rpx 30rpx;
margin-bottom: 20rpx;
}
.record-text {
font-size: 30rpx;
font-weight: 600;
color: #333;
}
.record-arrow {
font-size: 28rpx;
color: #999;
}
.card-type-tabs {
display: flex;
gap: 20rpx;
}
.tab-item {
flex: 1;
height: 80rpx;
line-height: 80rpx;
text-align: center;
background: #f5f5f5;
border-radius: 12rpx;
font-size: 28rpx;
color: #666;
transition: all 0.3s;
}
.tab-item.active {
background: #d81e06;
color: #fff;
}
.search-section {
background: #fff;
border-radius: 16rpx;
padding: 30rpx;
margin-bottom: 20rpx;
}
.search-box {
display: flex;
gap: 20rpx;
align-items: center;
}
.phone-input {
flex: 1;
height: 80rpx;
padding: 0 20rpx;
background: #f5f5f5;
border-radius: 12rpx;
font-size: 28rpx;
}
.search-btn {
width: 160rpx;
height: 80rpx;
line-height: 80rpx;
background: #d81e06;
color: #fff;
border-radius: 12rpx;
font-size: 28rpx;
padding: 0;
border: none;
}
.search-btn[disabled] {
background: #ccc;
}
.card-list-section {
background: #fff;
border-radius: 16rpx;
padding: 30rpx;
margin-bottom: 20rpx;
}
.card-list {
display: flex;
flex-direction: column;
gap: 20rpx;
}
.card-item {
padding: 30rpx;
background: #f5f5f5;
border-radius: 12rpx;
border: 2rpx solid transparent;
transition: all 0.3s;
}
.card-item.selected {
border-color: #d81e06;
background: #fff5f5;
}
.card-name {
font-size: 32rpx;
font-weight: 600;
color: #333;
margin-bottom: 10rpx;
}
.card-info {
font-size: 24rpx;
color: #666;
margin-bottom: 5rpx;
}
.card-balance {
font-size: 28rpx;
color: #d81e06;
font-weight: 600;
margin-top: 10rpx;
}
.amount-section {
background: #fff;
border-radius: 16rpx;
padding: 30rpx;
margin-bottom: 20rpx;
}
.amount-input-box {
display: flex;
align-items: center;
height: 100rpx;
padding: 0 20rpx;
background: #f5f5f5;
border-radius: 12rpx;
margin-bottom: 30rpx;
}
.currency {
font-size: 40rpx;
font-weight: 600;
color: #333;
margin-right: 10rpx;
}
.amount-input {
flex: 1;
font-size: 40rpx;
font-weight: 600;
color: #333;
}
.quick-amount {
display: flex;
gap: 20rpx;
flex-wrap: wrap;
}
.amount-btn {
flex: 1;
min-width: 150rpx;
height: 70rpx;
line-height: 70rpx;
text-align: center;
background: #f5f5f5;
border-radius: 12rpx;
font-size: 28rpx;
color: #666;
}
.submit-section {
padding: 30rpx;
}
.submit-btn {
width: 100%;
height: 90rpx;
line-height: 90rpx;
background: #d81e06;
color: #fff;
border-radius: 45rpx;
font-size: 32rpx;
font-weight: 600;
border: none;
}
</style>
+2 -2
View File
@@ -49,7 +49,7 @@
</uni-card>
</block>
<uv-gap height="20"></uv-gap>
<view class="save-btn" v-if="form.orderStatus == 0">
<view class="save-btn" v-if="form.orderStatus == 0 || form.orderStatus == 2">
<uv-button
:customStyle="{ background: 'linear-gradient(to right, #ccff66, #008e04)', borderRadius: '30px', color: '#ffffff' }"
text="确认核销"
@@ -95,7 +95,7 @@ export default {
loadMore: 'more',
logo: '',
items: ['全部订单', '未支付', '已支付', '已完成', '押金'],
orderStatus: ['未使用', '已完成', '已取消', '取消中', '退款申请中', '退款被拒绝', '退款成功', '客户端申请退款'],
orderStatus: ['', '已完成', '未使用', '已取消', '退款申请中', '退款被拒绝', '退款成功', '', '客户端申请退款', '未完成'],
payType: [
'余额支付',
'微信支付',
+49
View File
@@ -106,6 +106,13 @@
"enablePullDownRefresh": false
}
},
{
"path": "user/balance",
"style": {
"navigationBarTitleText": "我的余额",
"enablePullDownRefresh": false
}
},
{
"path": "user/balance-log",
"style": {
@@ -197,6 +204,20 @@
"enablePullDownRefresh": false
}
},
{
"path": "order/multiInvoice",
"style": {
"navigationBarTitleText": "场地发票",
"enablePullDownRefresh": false
}
},
{
"path": "order/doMultiInvoice",
"style": {
"navigationBarTitleText": "合并开票",
"enablePullDownRefresh": false
}
},
{
"path": "user/qrcode",
"style": {
@@ -438,6 +459,34 @@
"navigationBarTitleText": "门店商品",
"enablePullDownRefresh": false
}
},
{
"path": "user/offReq",
"style": {
"navigationBarTitleText": "折扣申请",
"enablePullDownRefresh": false
}
},
{
"path": "user/recharge-record",
"style": {
"navigationBarTitleText": "充值记录",
"enablePullDownRefresh": false
}
},
{
"path": "user/recharge",
"style": {
"navigationBarTitleText": "小额充值",
"enablePullDownRefresh": false
}
},
{
"path": "parking/index",
"style": {
"navigationBarTitleText": "停车缴费",
"enablePullDownRefresh": false
}
}
]
},
+34 -8
View File
@@ -100,7 +100,7 @@
<view v-if="activity && activity.title" @click="toArticle(activity.articleId)" style="width: 60vw"
class="p-30 pos-r bg-white rounded">
<view class="flex flex-col justify-center items-center">
<text class="text-orange font-bold my-20 text-35">热门活动</text>
<text class="text-orange font-bold my-20 text-35">公告</text>
<text class="my-20">{{ activity.title }}</text>
</view>
<view class="mt-20">
@@ -331,21 +331,47 @@ export default {
this.openUrl(pathList[index]);
},
openUrl(url) {
if (!this.isLogin) {
this.$refs.login.open('bottom');
return false;
} else {
// if (!this.isLogin) {
// this.$refs.login.open('bottom');
// return false;
// } else {
uni.navigateTo({
url
});
}
// }
},
onLayout({mpMenus, ads}) {
this.mpMenus = mpMenus;
this.mpMenus = this.applyParkingMenu(mpMenus);
this.ads = ads;
this.hideTools = false;
this.ad279 = this.getAdImageUrl(ads.find(d => d.adId === 279));
},
applyParkingMenu(mpMenus) {
if (!mpMenus || typeof mpMenus !== 'object') {
return mpMenus;
}
const icon = 'https://oss.wsdns.cn/20261013/566ec0e5017e4c698079d9403300d5cd.png?x-oss-process=image/resize,m_fixed,w_750/quality,Q_90';
const next = {...mpMenus};
Object.keys(next).forEach((key) => {
const menus = next[key];
if (!Array.isArray(menus)) {
return;
}
next[key] = menus.map((item) => {
if (!item || String(item.title || '').trim() !== '热点新闻') {
return item;
}
return {
...item,
title: '停车缴费',
avatar: icon,
path: '/package/parking/index',
target: 'uni.navigateTo'
};
});
});
return next;
},
getAdImageUrl(item) {
if (!item) {
return [];
@@ -497,7 +523,6 @@ page {
.merchant-card {
margin: 12rpx auto;
background: #ffffff;
border-radius: 10rpx;
border-color: slategrey;
border-radius: 16rpx;
@@ -512,6 +537,7 @@ page {
font-weight: 500;
font-size: 26rpx;
text-align: center;
min-height: 70rpx;
}
.merchant-desc {
+58 -22
View File
@@ -42,6 +42,32 @@
</view>
</view>
</template>
<template v-else-if="orderType === 1">
<view v-for="(item, index) in orderList" class="card m-20" :key="index">
<view class="pb-20 border-bottom flex justify-between items-center text-25">
<text>{{ item.orderNum }}</text>
<text v-if="item.status === 1" class="text-green">已支付,未退款</text>
<text v-if="item.status === 2">未支付</text>
<text v-if="item.status === 3" class="text-red">已退款</text>
</view>
<view class="py-20 border-bottom flex justify-between items-center text-25">
<text>{{ item.vipName }}</text>
<text class="text-red font-bold">¥{{ item.money }}</text>
</view>
<view class="py-20 flex justify-start items-center text-25 text-gray">
<text>{{ dayjs(item.createTime * 1000).format('YYYY-MM-DD HH:mm:ss') }}</text>
</view>
<view slot="actions" class="card-actions" v-if="item.status === 1">
<button class="mini-btn mx-10" size="mini" v-if="item.isInvoice === 2" @click="onInvoice(item)">
申请开票
</button>
<button class="mini-btn mx-10" size="mini" v-else-if="item.isInvoice === 1"
@click="showInvoice(item.id)">
查看发票
</button>
</view>
</view>
</template>
<template v-else>
<block v-for="(item,index) in orderList" :key="index">
<uni-card :border="false" :is-shadow="false" :padding="0">
@@ -118,7 +144,8 @@
@click="refund(item, index)" :disabled="item.disabled">
{{ item.payType === 1 ? '申请退款' : '取消订单' }}
</button>
<button class="mini-btn mx-10" size="mini" v-if="item.orderStatus === 2" @click="toDetail(item.id)">
<button type="primary" class="mini-btn mx-10" size="mini" v-if="item.orderStatus === 2"
@click="toDetail(item.id)">
核销码
</button>
<button class="mini-btn mx-10" size="mini" v-if="item.canInvoice" @click="onInvoice(item)">
@@ -200,6 +227,7 @@ import * as Api from "@/api/booking/userInvoice";
import {addThinkOrderRefundLog} from "@/api/think/thinkOrderRefundLog";
import {authUser} from "@/api/user";
import {useUserStore} from "@/store/modules/user";
import {pageThinkRechargeLog} from "@/api/think/thinkRechargeLog";
const userStore = useUserStore();
@@ -360,18 +388,19 @@ export default {
res = await pageThinkOrder(this.where).catch(err => {
this.$refs.login.open('bottom')
})
} else if (this.orderType === 1) res = await pageThinkUsersVip(this.where).catch(err => {
this.$refs.login.open('bottom')
})
else if (this.orderType === 2) res = await pageThinkDeposit(this.where).catch(err => {
} else if (this.orderType === 1) {
this.where.forUser = true
res = await pageThinkRechargeLog(this.where).catch(err => {
this.$refs.login.open('bottom')
})
} else if (this.orderType === 2) res = await pageThinkDeposit(this.where).catch(err => {
this.$refs.login.open('bottom')
})
if (this.orderList.length < res.count) {
let list = res.list
if (this.orderType === 1) list = list.map(item => {
item.orderNum = item.wechatOrder
item.payPrice = item.price
item.payPrice = item.money
return item
})
if (this.orderType === 0) list = list.map(item => {
@@ -399,7 +428,6 @@ export default {
return item
})
this.orderList = this.orderList.concat(list)
console.log(this.orderList)
this.canReset = true
this.loadMore = 'no-more'
} else {
@@ -408,12 +436,11 @@ export default {
}
if (this.orderType !== 2) {
this.orderList = this.orderList.map(item => {
// item.canInvoice = true
item.canInvoice = false
if (this.orderType === 0 && item.isInvoice === 2 && item.orderStatus === 1) {
const date = item.dateTime.split("(")[0]
const endTime = item.dateTime.split(" - ")[1]
const time = `${date} ${endTime}:00`
if (dayjs().isAfter(dayjs(time))) item.canInvoice = true
if (this.orderType === 0 && item.isInvoice === 2 && item.orderStatus === 1 && item.payPrice > 0) {
const startTime = item.startTime.split(',')[0]
if (dayjs().isAfter(dayjs(parseInt(startTime) * 1000))) item.canInvoice = true
}
return item
})
@@ -608,21 +635,30 @@ export default {
uni.showLoading({
title: '退款请求中'
})
await addThinkOrderRefundLog({
const res = await addThinkOrderRefundLog({
uid: order.uid,
refundAmount: order.price,
refundAmount: order.payPrice,
sid: order.sid,
oid: order.id,
status: 1,
type: 0
}).catch(async err => {
uni.showToast({
title: err.message,
icon: 'none'
});
this.orderList[index].disabled = false
await this.reload()
})
this.orderList[index].disabled = false
uni.hideLoading()
uni.showToast({
title: '申请退款成功',
icon: 'none'
})
await this.reload()
if (res) {
this.orderList[index].disabled = false
uni.hideLoading()
uni.showToast({
title: '申请退款成功',
icon: 'none'
})
await this.reload()
}
}
}
})
+1 -1
View File
@@ -138,7 +138,7 @@ export default {
if (uni.getStorageSync('user_id') && uni.getStorageSync('access_token')) {
this.isLogin = true;
}
this.list = await listThinkGoodsCategory()
this.list = await listThinkGoodsCategory({isShow: 1})
// console.log(this.list)
},
listCart() {
+314 -117
View File
@@ -1,7 +1,7 @@
<template>
<layout class="page" @done="onLayout">
<!-- 顶部距离 -->
<view class="header" :style="'height: ' + statusBarHeight + 'px'" @click="phoneLogin"> </view>
<view class="header" :style="'height: ' + statusBarHeight + 'px'" @click="phoneLogin"></view>
<!-- 用户信息 -->
<ws-user-card :data="userInfo" :users="users" :isLogin="isLogin" @openLogin="openLogin" @done="reload"/>
<block v-if="hideTools">
@@ -9,60 +9,31 @@
<uv-skeleton rows="2" :loading="hideTools" :title="false"></uv-skeleton>
</uni-card>
<uni-card :border="false" :padding="'18px 8px'">
<uv-skeleton rows="9" :loading="hideTools" :title="false"></uv-skeleton>
<uv-skeleton rows="12" :loading="hideTools" :title="false"></uv-skeleton>
</uni-card>
</block>
<block v-else>
<!-- 收藏|关注|足迹|作品 -->
<!-- <ws-user-collect></ws-user-collect> -->
<!-- 我的资产 -->
<ws-my-asset :data="userInfo" :users="users" :config="config" :is-login="isLogin" @done="openLogin"></ws-my-asset>
<!-- 我的订单 -->
<!-- <ws-user-order :order="order" :is-login="isLogin" @done="openLogin"></ws-user-order> -->
<!-- 其他功能 -->
<uni-card :border="false" :padding="0">
<!-- 场馆管理可见-->
<block v-if="hasMerchantRole || hasMerchantClerkRole">
<view class="card">
<block v-for="(item, index) in mpMenus" :key="index">
<block v-if="index === '1981'" v-for="(v, i) in item" :key="i">
<view class="flex justify-between items-center py-20 border-bottom" @click="navTo(v)">
<view class="flex justify-start items-center">
<uv-icon :name="v.avatar"/>
<text class="text-30 ml-20">{{ v.title }}</text>
</view>
<uv-icon name="arrow-right" size="24rpx"/>
</view>
</block>
</block>
<view class="flex justify-between items-center py-20 border-bottom" @click="showActionSheet">
<view class="flex justify-start items-center">
<uv-icon name="https://oss.wsdns.cn/20241126/92f728b3b4e146d6a916259bde11a209.png"/>
<text class="text-30 ml-20">扫码核销</text>
</view>
<uv-icon name="arrow-right" size="24rpx"/>
<view v-for="section in menuSections" :key="section.title" class="menu-section">
<uni-card :border="false" :padding="'8px 0'" :title="section.title">
<view class="menu-grid">
<view
v-for="item in section.items"
:key="item.title"
class="menu-grid-item"
@click="handleMenuClick(item)"
>
<image
v-if="item.avatar"
class="menu-avatar"
:src="item.avatar"
mode="aspectFit"
/>
<view v-else class="menu-icon" :style="{background: item.color}">{{ item.badge }}</view>
<text class="menu-title">{{ item.title }}</text>
</view>
</view>
</block>
<block v-else>
<!-- 普通会员菜单 -->
<view class="server" style="min-height: 200px">
<view class="card">
<block v-for="(item, index) in mpMenus" :key="index">
<block v-if="index === '1981'" v-for="(v, i) in item" :key="i">
<view class="flex justify-between items-center py-20 border-bottom" @click="navTo(v)">
<view class="flex justify-start items-center">
<uv-icon :name="v.avatar"/>
<text class="text-30 ml-20">{{ v.title }}</text>
</view>
<uv-icon name="arrow-right" size="24rpx"/>
</view>
</block>
</block>
</view>
</view>
</block>
</uni-card>
</uni-card>
</view>
<!-- 登录组件 -->
<ws-login ref="login" :logo="logo" @done="reload"/>
<!-- 退出按钮 -->
@@ -83,25 +54,23 @@
<script>
import {useUserStore} from '@/store/modules/user';
import * as MpMenuApi from '@/api/cms/mp-menu';
import * as UserCardApi from '@/api/booking/userCard';
import {getThinkUsers, updateThinkUsers} from '@/api/think/thinkUsers';
import {openUrl} from '@/utils/common';
import {getThinkUsers} from '@/api/think/thinkUsers';
import {useMpStore} from "@/store/modules/mp";
import {getWxOpenId, loginByOpenId} from '@/api/passport/login';
import Layout from "@/components/layout.vue";
import {useTenantStore} from '@/store/modules/tenant';
import {authUser, loginByPhoneReq} from "@/api/user";
import UvAvatar from "@/uni_modules/uv-avatar/components/uv-avatar/uv-avatar.vue";
import {getThinkOrderByCode, thinkOrderCheckCode} from "@/api/think/thinkOrder";
import {detectFace} from "@/api/think/thinkGate";
import {setHasFace} from "@/api/think/thinkUsers";
import {uploadFaceByPath} from "@/api/system/file";
const tenantStore = useTenantStore();
const mpStore = useMpStore();
const userStore = useUserStore();
export default {
components: {UvAvatar, Layout},
components: {Layout},
data() {
return {
statusBarHeight: 104,
@@ -110,13 +79,8 @@ export default {
fields: {},
logo: '',
config: {},
bookingUser: {},
merchantList: [],
server: [],
mpMenus: [],
ads: [],
order: [],
users: {},
mpMenus: {},
hideTools: true,
// 是否拥有场馆管理员权限
hasMerchantRole: false,
@@ -127,6 +91,130 @@ export default {
loginCount: 0
};
},
computed: {
menuSections() {
const commonFeatures = [
{
title: '我的余额',
badge: '额',
color: 'linear-gradient(135deg, #ff9a62 0%, #ff7a45 100%)',
url: '/package/user/balance',
avatar: 'https://oss.wsdns.cn/20260507/0006fc2aed2045fd863539fda6ac3c42.png'
},
{
title: '发票开具',
badge: '票',
color: 'linear-gradient(135deg, #6cc1ff 0%, #409eff 100%)',
url: '/package/user/invoice-type',
avatar: this.getMenuAvatar(['发票开具'])
},
{
title: '我的会员卡',
badge: '卡',
color: 'linear-gradient(135deg, #51d0c0 0%, #1abc9c 100%)',
url: '/package/user/card',
avatar: this.getMenuAvatar(['我的会员卡'])
},
{
title: '商城订单',
badge: '单',
color: 'linear-gradient(135deg, #7a8bff 0%, #5a67f8 100%)',
url: '/package/goods/order',
avatar: this.getMenuAvatar(['商城订单'])
},
{
title: '我的地址',
badge: '址',
color: 'linear-gradient(135deg, #7dd56f 0%, #28a745 100%)',
url: '/package/user/address',
avatar: this.getMenuAvatar(['我的地址'])
},
{
title: '交押金',
badge: '押',
color: 'linear-gradient(135deg, #ffb36b 0%, #ff8f1f 100%)',
url: '/package/user/depositList',
avatar: this.getMenuAvatar(['交押金'])
}
];
const otherTools = [
{
title: '紧急联系人',
badge: '联',
color: 'linear-gradient(135deg, #5fd1c7 0%, #23b3a7 100%)',
url: '/package/user/emergency',
avatar: this.getMenuAvatar(['紧急联系人'])
},
{
title: '优惠券',
badge: '券',
color: 'linear-gradient(135deg, #ff8fb1 0%, #ff5f8f 100%)',
url: '/package/user/coupon',
avatar: this.getMenuAvatar(['优惠券', '优惠劵'])
},
{
title: '我的积分',
badge: '分',
color: 'linear-gradient(135deg, #ffd36b 0%, #ffb020 100%)',
url: '/package/user/integral',
avatar: this.getMenuAvatar(['我的积分'])
},
{
title: 'IC卡激活',
badge: 'IC',
color: 'linear-gradient(135deg, #8f9bff 0%, #6c63ff 100%)',
url: '/package/user/ic-card',
avatar: this.getMenuAvatar(['IC卡激活'])
},
{
title: '电话客服',
badge: '服',
color: 'linear-gradient(135deg, #4fc3f7 0%, #0288d1 100%)',
url: '/package/user/phoneService',
requiresLogin: false,
avatar: this.getMenuAvatar(['电话客服'])
},
{
title: '关于我们',
badge: '关',
color: 'linear-gradient(135deg, #9da7b3 0%, #6b7280 100%)',
url: '/package/article/index?id=428',
requiresLogin: false,
avatar: this.getMenuAvatar(['关于我们'])
},
{
title: '扫码核销',
badge: '核',
color: 'linear-gradient(135deg, #ff9966 0%, #ff5e62 100%)',
avatar: 'https://oss.wsdns.cn/20241126/92f728b3b4e146d6a916259bde11a209.png',
action: 'scan',
visible: this.hasMerchantRole || this.hasMerchantClerkRole
},
// {
// title: '小额充值',
// badge: '充',
// color: 'linear-gradient(135deg, #66d9ef 0%, #2ca7c9 100%)',
// avatar: 'https://gxtyzx-server.websoft.top/api/file/20260107/%E5%85%85%E5%80%BC.png',
// url: '/package/user/recharge',
// visible: this.hasMerchantRole || this.hasMerchantClerkRole
// },
{
title: '更新人脸',
badge: '脸',
color: 'linear-gradient(135deg, #f7a35c 0%, #f15c80 100%)',
avatar: 'https://gxtyzx-api2.websoft.top/api/file/20260311/%E4%BA%BA%E8%84%B8%E8%AE%A4%E8%AF%81.png',
action: 'face',
visible: this.users.hasFace === 0
}
].filter((item) => item.visible !== false);
return [
{title: '常用功能', items: commonFeatures},
{title: '其他工具', items: otherTools}
];
}
},
onLoad() {
this.reload();
},
@@ -161,7 +249,7 @@ export default {
if (uni.getStorageSync('uid')) {
await getThinkUsers(uni.getStorageSync('uid')).then(data => {
app.users = data;
console.log(app.users, '>>>>')
// console.log(app.users, '>>>>')
})
}
// 当前登录用户信息
@@ -213,62 +301,44 @@ export default {
// }
// });
if (!uni.getStorageSync('openid')) {
// 更新openid
// #ifdef MP-WEIXIN
uni.login({
success: (res) => {
getWxOpenId({
code: res.code
}).then((response) => {
uni.setStorageSync('openid', response.openid);
updateUsers({
id: uni.getStorageSync('uid'),
openId: response.openid,
sessionKey: response.session_key,
unionid: response.unionid
});
});
}
});
// #endif
}
// if (!uni.getStorageSync('openid')) {
// // 更新openid
// // #ifdef MP-WEIXIN
// uni.login({
// success: (res) => {
// getWxOpenId({
// code: res.code
// }).then((response) => {
// uni.setStorageSync('openid', response.openid);
// updateUsers({
// id: uni.getStorageSync('uid'),
// openId: response.openid,
// sessionKey: response.session_key,
// unionid: response.unionid
// });
// });
// }
// });
// // #endif
// }
} else {
app.isLogin = false;
app.userInfo = {};
}
// 菜单数据
MpMenuApi.pageMpMenu({type: 0, limit: 100})
.then((res) => {
app.order = res.list.filter((d) => d.rows == 0);
app.server = res.list.filter((d) => d.rows == 1);
if (!app.hasMerchantRole && !app.hasMerchantClerkRole) {
app.server = res.list.filter((d) => d.rows == 1 && d.adminShow == 0);
}
app.hideTools = false;
})
.catch(() => {
uni.showToast({
title: '请检查您的网络.',
icon: 'none'
});
app.hideTools = false;
});
app.hideTools = false;
},
navTo(item) {
if (!this.isLogin) {
this.$refs.login.open('bottom');
return false;
} else {
openUrl(item);
}
},
onLayout({mpMenus, ads}) {
this.mpMenus = mpMenus;
this.ads = ads;
onLayout(data = {}) {
this.mpMenus = data.mpMenus || {};
this.hideTools = false;
},
getMenuAvatar(titles = []) {
const flatMenus = Object.values(this.mpMenus || [])
.filter((item) => Array.isArray(item))
.flat();
const target = flatMenus.find((item) => titles.includes(item.title));
return target?.avatar || '';
},
// 弹出登录提示框
openLogin(text) {
if (!this.isLogin) {
@@ -279,6 +349,23 @@ export default {
uni.navigateTo({url: text})
}
},
handleMenuClick(item) {
if (item.requiresLogin !== false && !this.isLogin) {
this.$refs.login.open('bottom');
return false;
}
if (item.action === 'scan') {
this.showActionSheet();
return;
}
if (item.action === 'face') {
this.updateFace();
return;
}
if (item.url) {
uni.navigateTo({url: item.url});
}
},
scan() {
uni.scanCode({
onlyFromCamera: true,
@@ -298,18 +385,75 @@ export default {
}
});
},
showActionSheet(){
showActionSheet() {
this.$refs.actionSheet.open()
},
selectActionSheet({name}){
updateFace() {
if (!this.isLogin) {
this.$refs.login.open('bottom');
return false;
}
uni.chooseImage({
count: 1,
sizeType: ['compressed'],
sourceType: ['camera'],
success: async ({tempFilePaths = []}) => {
if (!tempFilePaths.length) {
return;
}
uni.showLoading({
title: '识别中...',
mask: true
})
try {
const personPhoto = await uploadFaceByPath(tempFilePaths[0]);
const res = await detectFace({personPhoto});
// console.log(res)
if (res.code !== 0) {
return uni.showToast({
title: res.message,
icon: 'none'
});
}
const uid = uni.getStorageSync('uid');
if (uid) {
await setHasFace({uid, personPhoto});
}
uni.showToast({
title: '更新成功',
icon: 'success'
});
} catch (err) {
uni.showToast({
title: err?.message || err?.data || '人脸识别失败',
icon: 'none'
});
} finally {
setTimeout(() => {
this.updateFace()
uni.hideLoading();
}, 1500);
}
},
fail: (err) => {
if (err && err.errMsg && err.errMsg.indexOf('cancel') > -1) {
return;
}
uni.showToast({
title: '拍照失败',
icon: 'none'
});
}
});
},
selectActionSheet({name}) {
if (name === '订单核销') {
this.scan()
}
else if (name === '游泳年/月卡使用') {
} else if (name === '游泳年/月卡使用') {
this.useCard()
}
},
async useCard(){
async useCard() {
uni.scanCode({
onlyFromCamera: true,
success: async ({result}) => {
@@ -397,4 +541,57 @@ page {
width: 130rpx !important;
margin-bottom: 30rpx;
}
.menu-section {
margin-bottom: 24rpx;
}
.section-title {
padding: 0 24rpx 16rpx;
font-size: 30rpx;
font-weight: 600;
color: #303133;
}
.menu-grid {
display: grid;
grid-template-columns: repeat(3, 1fr);
gap: 12rpx 0;
padding: 10rpx 0;
}
.menu-grid-item {
min-height: 120rpx;
padding: 10rpx 8rpx;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
}
.menu-avatar {
width: 60rpx;
height: 60rpx;
}
.menu-icon {
width: 60rpx;
height: 60rpx;
border-radius: 20rpx;
color: #ffffff;
font-size: 24rpx;
font-weight: 600;
display: flex;
align-items: center;
justify-content: center;
}
.menu-title {
margin-top: 10rpx;
font-size: 26rpx;
line-height: 1.4;
color: #303133;
text-align: center;
word-break: break-all;
}
</style>