commit
5c5591d581
49 changed files with 5205 additions and 0 deletions
@ -0,0 +1,24 @@ |
|||
# Logs |
|||
logs |
|||
*.log |
|||
npm-debug.log* |
|||
yarn-debug.log* |
|||
yarn-error.log* |
|||
pnpm-debug.log* |
|||
lerna-debug.log* |
|||
|
|||
node_modules |
|||
dist |
|||
dist-ssr |
|||
*.local |
|||
|
|||
# Editor directories and files |
|||
.vscode/* |
|||
!.vscode/extensions.json |
|||
.idea |
|||
.DS_Store |
|||
*.suo |
|||
*.ntvs* |
|||
*.njsproj |
|||
*.sln |
|||
*.sw? |
@ -0,0 +1,3 @@ |
|||
{ |
|||
"recommendations": ["Vue.volar"] |
|||
} |
@ -0,0 +1,5 @@ |
|||
# Vue 3 + Vite |
|||
|
|||
This template should help get you started developing with Vue 3 in Vite. The template uses Vue 3 `<script setup>` SFCs, check out the [script setup docs](https://v3.vuejs.org/api/sfc-script-setup.html#sfc-script-setup) to learn more. |
|||
|
|||
Learn more about IDE Support for Vue in the [Vue Docs Scaling up Guide](https://vuejs.org/guide/scaling-up/tooling.html#ide-support). |
@ -0,0 +1,20 @@ |
|||
<!doctype html> |
|||
<html lang="en"> |
|||
<head> |
|||
<meta charset="UTF-8"/> |
|||
<link rel="icon" type="image/svg+xml" href="/public/favicon.ico"/> |
|||
<meta name="viewport" content="width=device-width, initial-scale=1.0"/> |
|||
<title>广西体育中心</title> |
|||
</head> |
|||
<body> |
|||
<div id="app"></div> |
|||
<script type="module" src="/src/main.js"></script> |
|||
</body> |
|||
</html> |
|||
|
|||
<style> |
|||
html, body { |
|||
margin: 0; |
|||
padding: 0; |
|||
} |
|||
</style> |
@ -0,0 +1,28 @@ |
|||
{ |
|||
"name": "gxtyzx-front", |
|||
"private": true, |
|||
"version": "0.0.0", |
|||
"type": "module", |
|||
"scripts": { |
|||
"dev": "vite --mode=dev", |
|||
"build": "vite build --mode=build", |
|||
"preview": "vite preview" |
|||
}, |
|||
"dependencies": { |
|||
"@element-plus/icons-vue": "^2.3.1", |
|||
"axios": "^1.7.9", |
|||
"dayjs": "^1.11.13", |
|||
"element-plus": "^2.9.3", |
|||
"pinia": "^2.3.0", |
|||
"vite-plugin-compression": "^0.5.1", |
|||
"vue": "^3.5.13", |
|||
"vue-router": "4" |
|||
}, |
|||
"devDependencies": { |
|||
"@vitejs/plugin-vue": "^5.2.1", |
|||
"autoprefixer": "^10.4.20", |
|||
"postcss": "^8.4.49", |
|||
"tailwindcss": "^3.4.17", |
|||
"vite": "^6.0.5" |
|||
} |
|||
} |
File diff suppressed because it is too large
@ -0,0 +1,6 @@ |
|||
module.exports = { |
|||
plugins: { |
|||
tailwindcss: {}, |
|||
autoprefixer: {}, |
|||
} |
|||
} |
After Width: | Height: | Size: 6.7 KiB |
After Width: | Height: | Size: 1.5 KiB |
@ -0,0 +1,21 @@ |
|||
<template> |
|||
<div> |
|||
<Login v-if="currentPage === '/Login'"/> |
|||
<Home v-else/> |
|||
</div> |
|||
</template> |
|||
|
|||
<script setup> |
|||
import {ref, watch} from 'vue' |
|||
import {useRoute} from 'vue-router' |
|||
import Login from '@/views/Login.vue' |
|||
import Home from '@/views/Home.vue' |
|||
|
|||
const route = useRoute() |
|||
|
|||
let currentPage = ref('/Index') |
|||
watch(route, (path) => { |
|||
currentPage.value = path.path |
|||
}) |
|||
|
|||
</script> |
@ -0,0 +1,5 @@ |
|||
import post, {SERVER_API} from "@/api/base.js"; |
|||
|
|||
export const loginReq = data => post(`${SERVER_API}/login`, data) |
|||
|
|||
export const changePwdReq = data => post(`${SERVER_API}/system/user/password`, data) |
@ -0,0 +1,86 @@ |
|||
import axios from "axios"; |
|||
import {getUserInfo, clearUserInfo} from "./common.js"; |
|||
import router from "@/router/index.js"; |
|||
import {ElMessage} from "element-plus"; |
|||
|
|||
export const SERVER_API = process.env.VUE_APP_SERVER_API |
|||
|
|||
axios.defaults.baseURL = process.env.VUE_APP_BASE_API |
|||
axios.interceptors.request.use( |
|||
config => { |
|||
const token = getUserInfo().token |
|||
if (token && token !== 'undefined') { |
|||
config.headers['Authorization'] = 'Bearer ' + token |
|||
} else { |
|||
if (config.url !== '/login') { |
|||
clearUserInfo() |
|||
router.push('Login') |
|||
} |
|||
} |
|||
config.headers.tenantId = 10150 |
|||
return config |
|||
}, |
|||
) |
|||
|
|||
axios.interceptors.response.use( |
|||
res => { |
|||
if (parseInt(res.data.code) !== 0) { |
|||
ElMessage.closeAll() |
|||
ElMessage({ |
|||
type: 'error', |
|||
message: res.data.message ?? '未知错误' |
|||
}) |
|||
if (parseInt(res.data.code) === 401) { |
|||
clearUserInfo() |
|||
router.push('Login') |
|||
} |
|||
} |
|||
return res |
|||
}, |
|||
error => { |
|||
if (parseInt(error.response.status) === 1) { |
|||
ElMessage.closeAll() |
|||
ElMessage({ |
|||
type: 'error', |
|||
message: error.response.data.error ?? error.response.data.message |
|||
}) |
|||
} |
|||
} |
|||
) |
|||
|
|||
const post = (url, formData) => { |
|||
return new Promise((resolve, reject) => { |
|||
axios.post(url, formData).then(res => { |
|||
if (res.data.code === 0) resolve(res.data) |
|||
else reject(res.data.message) |
|||
}) |
|||
}) |
|||
} |
|||
|
|||
export const put = (url, formData) => { |
|||
return new Promise((resolve, reject) => { |
|||
axios.put(url, formData).then(res => { |
|||
if (res.data.code === 0) resolve(res.data) |
|||
else reject(res.data.message) |
|||
}) |
|||
}) |
|||
} |
|||
|
|||
export const get = (url, params = null) => { |
|||
if (params) { |
|||
url += '?' |
|||
for (let key in params) { |
|||
if (params[key] !== null && params[key] !== '') url += `${key}=${params[key]}&` |
|||
} |
|||
} |
|||
const lastChar = url.charAt(url.length - 1); |
|||
if (lastChar === '&' || lastChar === '?') url = url.slice(0, -1) |
|||
return new Promise((resolve, reject) => { |
|||
axios.get(url).then(res => { |
|||
if (res.data.code === 0) resolve(res.data) |
|||
else reject(res.data.message) |
|||
}) |
|||
}) |
|||
} |
|||
|
|||
export default post |
@ -0,0 +1,25 @@ |
|||
import post from "@/api/base.js"; |
|||
|
|||
export const indexUrl = process.env.VUE_APP_RESOURCE_URL |
|||
|
|||
//保存用户信息
|
|||
export const setUserInfo = (user) => { |
|||
console.log(user) |
|||
if (user.user) window.localStorage.setItem("uid", user.user.userId); |
|||
if (user.user) window.localStorage.setItem("username", user.user.realName); |
|||
if (user.access_token) window.localStorage.setItem("token", user.access_token); |
|||
} |
|||
//获取用户信息
|
|||
export const getUserInfo = () => { |
|||
return { |
|||
uid: window.localStorage.uid, |
|||
username: window.localStorage.username, |
|||
token: window.localStorage.token, |
|||
}; |
|||
} |
|||
//清空用户信息
|
|||
export const clearUserInfo = () => { |
|||
window.localStorage.removeItem("uid"); |
|||
window.localStorage.removeItem("username"); |
|||
window.localStorage.removeItem("token"); |
|||
} |
@ -0,0 +1,7 @@ |
|||
import post, {get, SERVER_API} from "@/api/base.js"; |
|||
|
|||
export const pageDeposit = data => get(`think/think-deposit/page`, data) |
|||
|
|||
export const addDeposit = data => post(`think/think-deposit`, data) |
|||
|
|||
export const listDepositItem = data => get(`think/think-deposit-item`, data) |
@ -0,0 +1,4 @@ |
|||
import post, {get, SERVER_API} from "@/api/base.js"; |
|||
|
|||
export const listThinkField = data => get(`think/think-field`, data) |
|||
export const listThinkFieldWithTimeList = data => post(`think/think-field/withTimeList`, data) |
@ -0,0 +1,10 @@ |
|||
import post, {put, get, SERVER_API} from "@/api/base.js"; |
|||
|
|||
export const listThinkCard = data => get(`think/think-card`, data) |
|||
export const thinkCardInfo = id => get(`think/think-card/${id}`) |
|||
export const updateThinkCard = data => put(`think/think-card`, data) |
|||
export const pageCard = data => get(`think/think-card/page`, data) |
|||
export const addThinkCard = data => post('think/think-card', data) |
|||
export const addThinkCardLog = data => post('think/think-card-log', data) |
|||
export const thinkCardCodePay = (id, data) => post(`/think/think-card/codePay/${id}`, data) |
|||
export const thinkCardOfflinePayCheckReq = id => post(`/think/think-card/checkWechatPayRes/${id}`) |
@ -0,0 +1,10 @@ |
|||
import post, {get, put, SERVER_API} from "@/api/base.js"; |
|||
|
|||
export const pageOrder = data => get(`/think/think-order/page`, data) |
|||
|
|||
export const getThinkOrder = id => get(`/think/think-order/${id}`) |
|||
|
|||
export const addThinkOrder = data => post(`/think/think-order/add-from-device`, data) |
|||
export const thinkOrderCodePay = (id, data) => post(`/think/think-order/codePay/${id}`, data) |
|||
export const updateThinkOrder = data => put(`/think/think-order`, data) |
|||
export const offlinePayCheckReq = id => post(`/think/think-order/checkWechatPayRes/${id}`) |
@ -0,0 +1,3 @@ |
|||
import post, {get, SERVER_API} from "@/api/base.js"; |
|||
|
|||
export const printReq = data => post(`/print`, data) |
@ -0,0 +1,4 @@ |
|||
import post, {get, SERVER_API} from "@/api/base.js"; |
|||
|
|||
export const listThinkSite = data => get(`think/think-site`, data) |
|||
export const listThinkSiteTime = data => get(`think/think-site-time`, data) |
@ -0,0 +1,3 @@ |
|||
import post, {get} from "@/api/base.js"; |
|||
|
|||
export const listThinkVip = data => get('think/think-vip', data) |
@ -0,0 +1,3 @@ |
|||
import post, {get, SERVER_API} from "@/api/base.js"; |
|||
|
|||
export const pageUsersVip = data => get(`think/think-users-vip/page`, data) |
After Width: | Height: | Size: 827 KiB |
After Width: | Height: | Size: 496 B |
@ -0,0 +1,68 @@ |
|||
<template> |
|||
<el-dialog title="修改密码" v-model="showDialog" top="10px"> |
|||
<el-form label-width="100"> |
|||
<el-form-item label="原密码"> |
|||
<el-input v-model="oldPwd" type="password"/> |
|||
</el-form-item> |
|||
<el-form-item label="新密码"> |
|||
<el-input v-model="newPwd" type="password"/> |
|||
</el-form-item> |
|||
<el-form-item label="确认密码"> |
|||
<el-input v-model="confirmPwd" type="password"/> |
|||
</el-form-item> |
|||
</el-form> |
|||
<div slot="footer" class="dialog-footer"> |
|||
<el-button @click="showDialog = false">取 消</el-button> |
|||
<el-button type="primary" @click="changePwd">确 定</el-button> |
|||
</div> |
|||
</el-dialog> |
|||
</template> |
|||
|
|||
<script setup> |
|||
import {ref, watch} from 'vue' |
|||
import {ElMessage} from "element-plus"; |
|||
import {changePwdReq} from "@/api/admin.js"; |
|||
import {getUserInfo} from "@/api/common.js"; |
|||
|
|||
let showDialog = defineModel() |
|||
let oldPwd = ref(null) |
|||
let newPwd = ref(null) |
|||
let confirmPwd = ref(null) |
|||
const changePwd = async () => { |
|||
if (!oldPwd.value) { |
|||
ElMessage.error({ |
|||
message: '请输入原密码' |
|||
}); |
|||
return |
|||
} |
|||
if (!newPwd.value) { |
|||
ElMessage.error({ |
|||
message: '请输入新密码' |
|||
}); |
|||
return |
|||
} |
|||
if (!confirmPwd.value) { |
|||
ElMessage.error({ |
|||
message: '请输入确认密码' |
|||
}); |
|||
return |
|||
} |
|||
if (confirmPwd.value !== newPwd.value) { |
|||
ElMessage.error({ |
|||
message: '新密码与确认密码不一致' |
|||
}); |
|||
return |
|||
} |
|||
const res = await changePwdReq({ |
|||
userId: getUserInfo().uid, |
|||
password: newPwd.value, |
|||
}) |
|||
if (res) { |
|||
ElMessage.success({ |
|||
message: '修改成功' |
|||
}); |
|||
showDialog.value = false |
|||
} |
|||
} |
|||
|
|||
</script> |
@ -0,0 +1,136 @@ |
|||
<template> |
|||
<el-dialog |
|||
v-model="dialogVisible" |
|||
title="收取押金" |
|||
width="80%" |
|||
:before-close="reload" |
|||
> |
|||
<el-form label-width="120px"> |
|||
<el-form-item label="场馆"> |
|||
<el-select size="large" v-model="sid" placeholder="请选择场馆" @change="getDepositItem"> |
|||
<el-option |
|||
v-for="item in siteList" |
|||
:key="item.value" |
|||
:label="item.label" |
|||
:value="item.value"> |
|||
</el-option> |
|||
</el-select> |
|||
</el-form-item> |
|||
<el-form-item label="抵押物品"> |
|||
<el-select size="large" v-model="formData.itemId" placeholder="请选择抵押物品" @change="selectItem"> |
|||
<el-option |
|||
v-for="item in depositItemList" |
|||
:key="item.value" |
|||
:label="item.title" |
|||
:value="item.id"> |
|||
</el-option> |
|||
</el-select> |
|||
</el-form-item> |
|||
<el-form-item label="抵押物品备注"> |
|||
<el-input size="large" v-model="formData.remark"></el-input> |
|||
</el-form-item> |
|||
<el-form-item label="押金金额"> |
|||
<el-input size="large" v-model="formData.money" disabled></el-input> |
|||
</el-form-item> |
|||
<el-form-item label="付款方式" required> |
|||
<el-select size="large" v-model="formData.moneyType" placeholder="支付方式选择" style="width: 160px;" clearable> |
|||
<el-option :value="1" label="微信支付"/> |
|||
<el-option :value="2" label="支付宝"/> |
|||
<el-option :value="3" label="现金"/> |
|||
<el-option :value="4" label="POS机"/> |
|||
</el-select> |
|||
</el-form-item> |
|||
<el-form-item label="支付凭证" required> |
|||
<el-input size="large" v-model="formData.money" disabled></el-input> |
|||
</el-form-item> |
|||
</el-form> |
|||
<template #footer> |
|||
<div class="flex justify-center items-center"> |
|||
<el-button size="large" @click="save" type="success" round style="width: 300px">收取</el-button> |
|||
<el-button size="large" @click="reload" type="danger" plain round style="width: 200px">关闭</el-button> |
|||
</div> |
|||
</template> |
|||
</el-dialog> |
|||
</template> |
|||
|
|||
<script setup> |
|||
|
|||
import {onMounted, reactive, ref} from "vue"; |
|||
import {listThinkVip} from "@/api/thinkVip.js"; |
|||
import {ElMessage} from "element-plus"; |
|||
import {addThinkCard, addThinkCardLog, listThinkCard, pageCard} from "@/api/icCard.js"; |
|||
import {reloadFlagStore} from "@/store/index.js"; |
|||
import dayjs from "dayjs"; |
|||
import {listThinkSite} from "@/api/site.js"; |
|||
import {addDeposit, listDepositItem} from "@/api/deposit.js"; |
|||
|
|||
const dialogVisible = defineModel() |
|||
|
|||
const defaultData = { |
|||
itemId: null, |
|||
type: 1, |
|||
money: null, |
|||
moneyType: null, |
|||
siteName: '', |
|||
name: '-', |
|||
phone: '-', |
|||
info: '', |
|||
remark: '', |
|||
isAdmin: true, |
|||
} |
|||
|
|||
let formData = reactive({...defaultData}) |
|||
|
|||
const save = async () => { |
|||
if (formData.remark) { |
|||
formData.info = `${formData.info}(${formData.remark})` |
|||
} |
|||
if (formData.moneyType !== 1) formData.status = 1 |
|||
const res = await addDeposit(formData) |
|||
if (res) { |
|||
ElMessage.success('记录成功') |
|||
formData = {...defaultData} |
|||
reload() |
|||
} |
|||
} |
|||
|
|||
const sid = ref(null) |
|||
const siteList = ref([]) |
|||
const getSiteList = async () => { |
|||
const res = await listThinkSite({}) |
|||
if (res) { |
|||
siteList.value = res.data.map(item => { |
|||
return { |
|||
value: item.id, |
|||
label: item.name |
|||
} |
|||
}) |
|||
} |
|||
} |
|||
|
|||
const depositItemList = ref([]) |
|||
const getDepositItem = async () => { |
|||
const site = siteList.value.find(item => item.value === sid.value) |
|||
formData.siteName = site.label |
|||
const {data} = await listDepositItem({ |
|||
sid: sid.value |
|||
}) |
|||
depositItemList.value = data |
|||
} |
|||
|
|||
const selectItem = () => { |
|||
const item = depositItemList.value.find(item => item.id === formData.itemId) |
|||
formData.money = item.amount |
|||
} |
|||
|
|||
const store = reloadFlagStore() |
|||
const reload = () => { |
|||
store.setData(true) |
|||
dialogVisible.value = false |
|||
} |
|||
|
|||
onMounted(() => { |
|||
store.setData(false) |
|||
getSiteList() |
|||
}) |
|||
</script> |
@ -0,0 +1,80 @@ |
|||
<template> |
|||
<el-dialog |
|||
v-model="dialogVisible" |
|||
title="IC卡详情" |
|||
width="60%" |
|||
:before-close="reload" |
|||
> |
|||
<el-descriptions :column="2" v-if="cardInfo" border> |
|||
<el-descriptions-item label="卡名称">{{ cardInfo.name }}</el-descriptions-item> |
|||
<el-descriptions-item label="卡号">{{ cardInfo.code }}</el-descriptions-item> |
|||
<el-descriptions-item label="姓名"> |
|||
<el-input v-model="cardInfo.username" @blur="changeField($event, 'username')"></el-input> |
|||
</el-descriptions-item> |
|||
<el-descriptions-item label="手机号"> |
|||
<el-input v-model="cardInfo.phone" @blur="changeField($event, 'phone')"></el-input> |
|||
</el-descriptions-item> |
|||
<el-descriptions-item label="身份证号">{{ cardInfo.idcard }}</el-descriptions-item> |
|||
<el-descriptions-item label="过期时间">{{ |
|||
dayjs(cardInfo.createTime * 1000).format('YYYY-MM-DD HH:mm:ss') |
|||
}} |
|||
</el-descriptions-item> |
|||
<el-descriptions-item label="剩余次数">{{ cardInfo.num }}</el-descriptions-item> |
|||
<el-descriptions-item label="剩余金额">{{ cardInfo.remainingMoney }}元</el-descriptions-item> |
|||
<el-descriptions-item label="可用场馆"> |
|||
{{ |
|||
cardInfo.siteList.map(item => item.name).join() |
|||
}} |
|||
</el-descriptions-item> |
|||
</el-descriptions> |
|||
<template #footer> |
|||
<el-space> |
|||
<el-button @click="reload" size="large">关闭</el-button> |
|||
</el-space> |
|||
</template> |
|||
</el-dialog> |
|||
|
|||
</template> |
|||
|
|||
<script setup> |
|||
|
|||
import {reloadFlagStore} from "@/store/index.js"; |
|||
import {onMounted, ref} from "vue"; |
|||
import dayjs from "dayjs"; |
|||
import {pageCard, thinkCardInfo, updateThinkCard} from "@/api/icCard.js"; |
|||
import {ElMessage} from "element-plus"; |
|||
|
|||
const props = defineProps({ |
|||
id: Number |
|||
}) |
|||
|
|||
const dialogVisible = defineModel() |
|||
|
|||
const cardInfo = ref(null) |
|||
const getInfo = async () => { |
|||
const {data} = await thinkCardInfo(props.id) |
|||
cardInfo.value = data |
|||
} |
|||
|
|||
const changeField = async (e, field) => { |
|||
const res = await updateThinkCard({ |
|||
id: props.id, |
|||
[field]: e.target.value |
|||
}) |
|||
if (res && res.code === 0) ElMessage.success('修改成功') |
|||
} |
|||
|
|||
onMounted(() => { |
|||
store.setData(false) |
|||
getInfo() |
|||
}) |
|||
|
|||
const emits = defineEmits(['close']) |
|||
|
|||
const store = reloadFlagStore() |
|||
const reload = () => { |
|||
store.setData(true) |
|||
dialogVisible.value = false |
|||
emits('close') |
|||
} |
|||
</script> |
@ -0,0 +1,296 @@ |
|||
<template> |
|||
<el-dialog |
|||
v-model="dialogVisible" |
|||
title="开卡" |
|||
width="80%" |
|||
:before-close="reload" |
|||
> |
|||
<el-form label-width="120px"> |
|||
<el-row :gutter="10"> |
|||
<el-col :span="12"> |
|||
<el-form-item label="卡名称" required> |
|||
<el-select size="large" v-model="formData.vid" placeholder="请选择VIP卡" @change="selectCard" filterable> |
|||
<el-option |
|||
v-for="item in vipList" |
|||
:key="item.id" |
|||
:label="item.name" |
|||
:value="item.id"> |
|||
</el-option> |
|||
</el-select> |
|||
</el-form-item> |
|||
<el-form-item label="VIP卡金额"> |
|||
<el-input size="large" v-model="formData.price" disabled placeholder="请选择VIP卡"/> |
|||
</el-form-item> |
|||
<el-form-item label="VIP卡月限"> |
|||
<el-input size="large" v-model="formData.month" disabled placeholder="请选择VIP卡"> |
|||
<template #append>月</template> |
|||
</el-input> |
|||
</el-form-item> |
|||
<el-form-item label="VIP卡年限"> |
|||
<el-input size="large" v-model="formData.term" disabled placeholder="请选择VIP卡"> |
|||
<template #append>年</template> |
|||
</el-input> |
|||
</el-form-item> |
|||
<el-form-item label="VIP卡折扣"> |
|||
<el-input size="large" v-model="formData.discount" disabled placeholder="请选择VIP卡"> |
|||
<template #append>折</template> |
|||
</el-input> |
|||
</el-form-item> |
|||
<el-form-item label="VIP卡类型"> |
|||
<el-select size="large" v-model="formData.type" placeholder="请选择VIP卡" disabled> |
|||
<el-option label="年卡" :value="1"/> |
|||
<el-option label="次卡" :value="2"/> |
|||
<el-option label="月卡" :value="3"/> |
|||
<el-option label="会员IC卡" :value="4"/> |
|||
<el-option label="充值卡" :value="5"/> |
|||
</el-select> |
|||
</el-form-item> |
|||
<el-form-item label="使用次数"> |
|||
<el-input size="large" v-model="formData.count" disabled placeholder="请选择VIP卡"> |
|||
<template #append>次</template> |
|||
</el-input> |
|||
</el-form-item> |
|||
<el-form-item label="每次减少"> |
|||
<el-input size="large" v-model="formData.eachMoney" disabled placeholder="请选择VIP卡"> |
|||
<template #append>元</template> |
|||
</el-input> |
|||
</el-form-item> |
|||
</el-col> |
|||
<el-col :span="12"> |
|||
<el-form-item label="手机号"> |
|||
<el-input size="large" v-model="formData.phone" placeholder="请输入手机号"/> |
|||
</el-form-item> |
|||
<el-form-item label="身份证号"> |
|||
<el-input size="large" v-model="formData.idcard" placeholder="请输入身份证号"/> |
|||
</el-form-item> |
|||
<el-form-item label="用户姓名"> |
|||
<el-input size="large" v-model="formData.username" placeholder="请输入用户姓名"/> |
|||
</el-form-item> |
|||
<el-form-item label="支付方式" required> |
|||
<el-select size="large" v-model="formData.payType" placeholder="请选择支付方式"> |
|||
<el-option label="微信支付" :value="1"/> |
|||
<el-option label="支付宝支付" :value="2"/> |
|||
<el-option label="现金" :value="3"/> |
|||
<el-option label="POS机刷卡" :value="4"/> |
|||
<el-option label="平安健康卡" :value="5"/> |
|||
</el-select> |
|||
</el-form-item> |
|||
<el-form-item label="支付凭证" required v-if="formData.payType !== 1"> |
|||
<el-input size="large" v-model="formData.wechatOrder" placeholder="请输入微信支付号/支付凭证号/收据单号"/> |
|||
</el-form-item> |
|||
<el-form-item label="支付密码"> |
|||
<el-input size="large" v-model="formData.password" placeholder="可留空"/> |
|||
</el-form-item> |
|||
<el-form-item label="确认支付密码"> |
|||
<el-input size="large" v-model="formData.confirmPassword" placeholder="可留空"/> |
|||
</el-form-item> |
|||
<el-form-item label="紧急联系人"> |
|||
<el-input size="large" v-model="formData.urgentName" placeholder="请输入紧急联系人"/> |
|||
</el-form-item> |
|||
<el-form-item label="紧急联系人电话"> |
|||
<el-input size="large" v-model="formData.urgentPhone" placeholder="请输入紧急联系人电话"/> |
|||
</el-form-item> |
|||
<el-form-item> |
|||
<el-button size="large" type="primary" :disabled="!formData.vid || !formData.payType" style="width: 100%" |
|||
@click="save"> |
|||
确认开卡 |
|||
</el-button> |
|||
</el-form-item> |
|||
</el-col> |
|||
</el-row> |
|||
</el-form> |
|||
<template #footer> |
|||
<div> |
|||
<el-button @click="reload">关闭</el-button> |
|||
</div> |
|||
</template> |
|||
</el-dialog> |
|||
<el-dialog v-model="showAuthCodeInput" title="扫码支付" append-to-body :close-on-click-modal="false" |
|||
@close="close"> |
|||
<p class="mt-2">扫码/输入微信支付码</p> |
|||
<el-input class="mt-2" v-model="authCode" ref="authCodeInput" @input="onCodeInput" @keyup.enter.native="doPay"/> |
|||
<div slot="footer" class="text-center mt-2"> |
|||
<el-space> |
|||
<el-button type="success" size="large" @click="doPay" |
|||
:disabled="!authCode"> |
|||
确认支付 |
|||
</el-button> |
|||
<el-button @click="showAuthCodeInput = false" size="large">关闭</el-button> |
|||
</el-space> |
|||
</div> |
|||
</el-dialog> |
|||
</template> |
|||
|
|||
<script setup> |
|||
|
|||
import {nextTick, onMounted, reactive, ref} from "vue"; |
|||
import {listThinkVip} from "@/api/thinkVip.js"; |
|||
import {ElLoading, ElMessage} from "element-plus"; |
|||
import {addThinkCard, addThinkCardLog, thinkCardCodePay, thinkCardOfflinePayCheckReq} from "@/api/icCard.js"; |
|||
import {reloadFlagStore} from "@/store/index.js"; |
|||
import {offlinePayCheckReq, thinkOrderCodePay} from "@/api/order.js"; |
|||
|
|||
const dialogVisible = defineModel() |
|||
|
|||
const defaultData = { |
|||
sid: null, |
|||
uid: null, |
|||
vid: null, |
|||
aid: null, |
|||
wechatOrder: null, |
|||
code: null, |
|||
name: null, |
|||
username: '', |
|||
phone: '', |
|||
price: null, |
|||
desc: null, |
|||
info: null, |
|||
discount: null, |
|||
count: null, |
|||
eachMoney: null, |
|||
remainingMoney: null, |
|||
number: null, |
|||
num: null, |
|||
status: 2, |
|||
term: null, |
|||
month: null, |
|||
type: null, |
|||
cardType: null, |
|||
vipType: null, |
|||
pic: null, |
|||
prices: null, |
|||
payType: null, |
|||
isIntegral: null, |
|||
isInvoice: null, |
|||
expireTime: null, |
|||
makeNum: null, |
|||
urgentName: null, |
|||
urgentPhone: null, |
|||
cardNum: null, |
|||
password: null, |
|||
useTime: null, |
|||
createTime: null, |
|||
idcard: null, |
|||
confirmPassword: null, |
|||
payVoucher: null, |
|||
|
|||
} |
|||
|
|||
const selectCard = id => { |
|||
const card = vipList.value.find(item => item.id === id) |
|||
formData.name = card.name |
|||
formData.price = card.price |
|||
formData.month = card.month |
|||
formData.term = card.term |
|||
formData.discount = card.discount |
|||
formData.type = card.type |
|||
formData.cardType = card.cardType |
|||
formData.vipType = card.vipType |
|||
formData.prices = card.prices |
|||
formData.eachMoney = card.eachMoney |
|||
formData.desc = card.desc |
|||
formData.info = card.info |
|||
formData.num = card.count |
|||
formData.count = card.count |
|||
formData.sort = card.sort |
|||
formData.sid = card.sid |
|||
formData.uid = 0 |
|||
|
|||
} |
|||
|
|||
let formData = reactive({...defaultData}) |
|||
|
|||
const newCardId = ref(null) |
|||
const save = async () => { |
|||
if (formData.password && !formData.confirmPassword) { |
|||
ElMessage.error('请输入确认密码') |
|||
return |
|||
} |
|||
if (formData.password && formData.password !== formData.confirmPassword) { |
|||
ElMessage.error('两次密码不一致') |
|||
return |
|||
} |
|||
if (formData.payType !== 1 && !formData.wechatOrder) { |
|||
ElMessage.error('请输入支付凭证') |
|||
return |
|||
} |
|||
if (formData.payType !== 1) { |
|||
formData.status = 1 |
|||
} |
|||
const res = await addThinkCard(formData) |
|||
if (res) { |
|||
if (formData.payType === 1) { |
|||
newCardId.value = res.data |
|||
authCode.value = '' |
|||
showAuthCodeInput.value = true |
|||
setTimeout(() => { |
|||
nextTick(() => { |
|||
authCodeInput.value.focus() |
|||
}) |
|||
}, 0) |
|||
} else { |
|||
ElMessage.success('开卡成功') |
|||
formData = {...defaultData} |
|||
reload() |
|||
} |
|||
} |
|||
} |
|||
|
|||
const showAuthCodeInput = ref(false) |
|||
const authCode = ref('') |
|||
const authCodeInput = ref(null) |
|||
|
|||
const onCodeInput = e => { |
|||
if (e.length === 18) doPay() |
|||
} |
|||
|
|||
const doPay = async () => { |
|||
const loadingInstance = ElLoading.service({fullscreen: true, text: '支付中'}) |
|||
const pay_method = parseInt(authCode.value.substring(0, 2)) < 20 ? 0 : 1 |
|||
if (pay_method === 1) { |
|||
ElMessage.error({message: '不支持支付宝'}) |
|||
return |
|||
} |
|||
await thinkCardCodePay(newCardId.value, {code: authCode.value}).catch(() => { |
|||
loadingInstance.close() |
|||
}) |
|||
await checkPayRes() |
|||
loadingInstance.close() |
|||
} |
|||
|
|||
const checkPayRes = async () => { |
|||
const loadingInstance = ElLoading.service({fullscreen: true, text: '等待用户输入支付密码'}) |
|||
const {data} = await thinkCardOfflinePayCheckReq(newCardId.value) |
|||
if (data.state === 'SUCCESS') { |
|||
loadingInstance.close() |
|||
ElMessage.success({message: '支付成功'}) |
|||
setTimeout(() => { |
|||
reload() |
|||
}, 1000) |
|||
}else if (data.state === 'PAYERROR') { |
|||
loadingInstance.close() |
|||
ElMessage.error({message: '支付失败'}) |
|||
setTimeout(() => { |
|||
reload() |
|||
}, 1000) |
|||
} else await checkPayRes() |
|||
} |
|||
|
|||
|
|||
const vipList = ref([]) |
|||
const getVipList = async () => { |
|||
const {data} = await listThinkVip() |
|||
vipList.value = data |
|||
} |
|||
|
|||
const store = reloadFlagStore() |
|||
const reload = () => { |
|||
store.setData(true) |
|||
dialogVisible.value = false |
|||
} |
|||
|
|||
onMounted(() => { |
|||
store.setData(false) |
|||
getVipList() |
|||
}) |
|||
</script> |
@ -0,0 +1,349 @@ |
|||
<template> |
|||
<el-dialog |
|||
v-model="dialogVisible" |
|||
title="订单详情" |
|||
width="60%" |
|||
:before-close="reload" |
|||
> |
|||
<el-descriptions :column="2" v-if="orderInfo"> |
|||
<el-descriptions-item label="订单号">{{ orderInfo.orderNo }}</el-descriptions-item> |
|||
<el-descriptions-item label="微信订单号">{{ orderInfo.wechatOrder }}</el-descriptions-item> |
|||
<el-descriptions-item label="姓名">{{ orderInfo.name }}</el-descriptions-item> |
|||
<el-descriptions-item label="手机号">{{ orderInfo.phone }}</el-descriptions-item> |
|||
<el-descriptions-item label="场馆名称">{{ orderInfo.siteName }}</el-descriptions-item> |
|||
<el-descriptions-item label="下单时间">{{ |
|||
dayjs(orderInfo.createTime * 1000).format('YYYY-MM-DD HH:mm:ss') |
|||
}} |
|||
</el-descriptions-item> |
|||
<el-descriptions-item label="订单状态"> |
|||
<span v-if="orderInfo.orderStatus === 1" class="text-green-500" |
|||
>已完成</span> |
|||
<span v-if="orderInfo.orderStatus === 2" class="ele-text-placeholder" |
|||
>未使用</span> |
|||
<span v-if="orderInfo.orderStatus === 3" class="text-gray-400" |
|||
>已取消</span> |
|||
<span v-if="orderInfo.orderStatus === 4" class="ele-text-warning" |
|||
>退款申请中</span> |
|||
<span v-if="orderInfo.orderStatus === 5">退款被拒绝</span> |
|||
<span v-if="orderInfo.orderStatus === 6">退款成功</span> |
|||
<span v-if="orderInfo.orderStatus === 7">客户端申请退款</span> |
|||
<span v-if="orderInfo.orderStatus === 9">未完成</span> |
|||
</el-descriptions-item> |
|||
<el-descriptions-item label="微信昵称">{{ orderInfo.username ?? '无' }}</el-descriptions-item> |
|||
<el-descriptions-item label="优惠说明">{{ orderInfo.desc }}</el-descriptions-item> |
|||
<el-descriptions-item label="支付状态"> |
|||
<span class="text-green-500" v-if="orderInfo.payStatus === 1">已支付</span> |
|||
<span class="text-red-500" v-if="orderInfo.payStatus === 2">未支付</span> |
|||
<span v-if="orderInfo.payStatus === 0 || orderInfo.payStatus === 3">未付款,占场中</span> |
|||
</el-descriptions-item> |
|||
<el-descriptions-item label="订单金额"> |
|||
<span class="text-xl font-bold">{{ orderInfo.totalPrice }}元</span> |
|||
</el-descriptions-item> |
|||
<el-descriptions-item label="支付方式"> |
|||
<!-- <el-tag v-if="orderInfo.payType === 0">余额支付</el-tag>--> |
|||
<el-tag v-if="orderInfo.payType === 1" type="success"> |
|||
微信支付 |
|||
</el-tag> |
|||
<el-tag v-if="orderInfo.payType === 2">积分</el-tag> |
|||
<el-tag v-if="orderInfo.payType === 3"> |
|||
支付宝 |
|||
</el-tag> |
|||
<el-tag v-if="orderInfo.payType === 4"> |
|||
现金 |
|||
</el-tag> |
|||
<el-tag v-if="orderInfo.payType === 5"> |
|||
POS机 |
|||
</el-tag> |
|||
<el-tag v-if="orderInfo.payType === 6" type="warning"> |
|||
VIP月卡 |
|||
</el-tag> |
|||
<el-tag v-if="orderInfo.payType === 7" type="warning"> |
|||
VIP年卡 |
|||
</el-tag> |
|||
<el-tag v-if="orderInfo.payType === 8" type="warning"> |
|||
VIP次卡 |
|||
</el-tag> |
|||
<el-tag v-if="orderInfo.payType === 9" type="danger"> |
|||
IC月卡 |
|||
</el-tag> |
|||
<el-tag v-if="orderInfo.payType === 10" type="danger"> |
|||
IC年卡 |
|||
</el-tag> |
|||
<el-tag v-if="orderInfo.payType === 11" type="danger"> |
|||
IC次卡 |
|||
</el-tag> |
|||
<el-tag v-if="orderInfo.payType === 12"> |
|||
免费 |
|||
</el-tag> |
|||
<el-tag v-if="orderInfo.payType === 13" type="warning"> |
|||
VIP充值卡 |
|||
</el-tag> |
|||
<el-tag v-if="orderInfo.payType === 14" type="danger"> |
|||
IC充值卡 |
|||
</el-tag> |
|||
<el-tag v-if="orderInfo.payType === 15"> |
|||
积分支付 |
|||
</el-tag> |
|||
<el-tag v-if="orderInfo.payType === 16" type="warning"> |
|||
VIP季卡 |
|||
</el-tag> |
|||
<el-tag v-if="orderInfo.payType === 17" type="danger"> |
|||
IC季卡 |
|||
</el-tag> |
|||
</el-descriptions-item> |
|||
<el-descriptions-item label="实付金额"> |
|||
<span class="text-xl font-bold">{{ orderInfo.payPrice }}元</span> |
|||
</el-descriptions-item> |
|||
</el-descriptions> |
|||
<el-table v-if="orderInfo" :data="orderInfo.thinkOrderInfos" style="width: 100%" stripe border |
|||
:header-cell-style="{backgroundColor: '#22C55E', color: '#FFF'}" |
|||
:cell-style="{backgroundColor: '#e2ffec'}"> |
|||
<el-table-column prop="fieldName" label="场地名称" fixed width="200"/> |
|||
<el-table-column prop="price" label="成人价"/> |
|||
<el-table-column prop="childrenPrice" label="儿童价"/> |
|||
<el-table-column prop="dateTime" label="场地预约时间" width="300"/> |
|||
<el-table-column prop="adultNum" label="成人数"/> |
|||
<el-table-column prop="childrenNum" label="儿童数"/> |
|||
<el-table-column label="是否支持儿童票" v-slot="scope"> |
|||
<span>{{ scope.row.isChildren === 1 ? '支持' : '不支持' }}</span> |
|||
</el-table-column> |
|||
</el-table> |
|||
<template #footer> |
|||
<el-space> |
|||
<el-button type="success" size="large" v-if="orderInfo && orderInfo.payStatus !== 1" @click="showPay = true"> |
|||
立即支付 |
|||
</el-button> |
|||
<el-button type="primary" size="large" @click.native="print" :disabled="disablePrint" |
|||
v-if="orderInfo && orderInfo.payStatus !== 2">打印 |
|||
</el-button> |
|||
<el-button @click="reload" size="large">关闭</el-button> |
|||
</el-space> |
|||
</template> |
|||
</el-dialog> |
|||
<el-dialog |
|||
v-model="showPay" |
|||
title="订单支付" |
|||
width="50%" |
|||
> |
|||
<el-form label-width="80px"> |
|||
<el-form-item label="支付方式"> |
|||
<el-select v-model="formData.payType" required> |
|||
<el-option label="微信支付" :value="1"/> |
|||
<el-option label="现金" :value="4"/> |
|||
<el-option label="POS(银行卡/支付宝)" :value="5"/> |
|||
<el-option label="IC卡" :value="-1"/> |
|||
<el-option label="免费" :value="12"/> |
|||
</el-select> |
|||
</el-form-item> |
|||
<el-form-item label="IC卡选择" required v-if="formData.payType === -1"> |
|||
<el-select v-model="formData.cid" placeholder="姓名/手机号/卡号搜索" filterable |
|||
:remote-method="searchCard" |
|||
@change="selectUserCard" remote> |
|||
<el-option |
|||
v-for="item in userCard" |
|||
:key="item.id" |
|||
:label="item.title" |
|||
:value="item.id"> |
|||
</el-option> |
|||
</el-select> |
|||
</el-form-item> |
|||
<el-form-item label="支付凭证" required v-if="formData.payType === 4 || formData.payType === 5"> |
|||
<el-input v-model="formData.wechatOrder" placeholder="请输入支付凭证"></el-input> |
|||
</el-form-item> |
|||
|
|||
</el-form> |
|||
<template #footer> |
|||
<el-space> |
|||
<el-button type="success" size="large" @click="selectPay" |
|||
:disabled="(formData.payType === -1 && !formData.cid) || ((formData.payType === 4 || formData.payType === 5) && !formData.wechatOrder)"> |
|||
确认支付 |
|||
</el-button> |
|||
<el-button @click="closePay" size="large">关闭</el-button> |
|||
</el-space> |
|||
</template> |
|||
</el-dialog> |
|||
<el-dialog v-model="showAuthCodeInput" title="扫码支付" append-to-body :close-on-click-modal="false" |
|||
@close="close"> |
|||
<p class="mt-2">扫码/输入微信支付码</p> |
|||
<el-input class="mt-2" v-model="authCode" ref="authCodeInput" @input="onCodeInput" @keyup.enter.native="doPay"/> |
|||
<div slot="footer" class="text-center mt-2"> |
|||
<el-space> |
|||
<el-button type="success" size="large" @click="doPay" |
|||
:disabled="!authCode || disabledPay"> |
|||
确认支付 |
|||
</el-button> |
|||
<el-button @click="showAuthCodeInput = false" size="large">关闭</el-button> |
|||
</el-space> |
|||
</div> |
|||
</el-dialog> |
|||
</template> |
|||
|
|||
<script setup> |
|||
|
|||
import {reloadFlagStore} from "@/store/index.js"; |
|||
import {getThinkOrder, offlinePayCheckReq, thinkOrderCodePay, updateThinkOrder} from "@/api/order.js"; |
|||
import {nextTick, onMounted, ref} from "vue"; |
|||
import dayjs from "dayjs"; |
|||
import {pageCard, updateThinkCard} from "@/api/icCard.js"; |
|||
import {printReq} from "@/api/print.js"; |
|||
import {ElLoading, ElMessage} from "element-plus"; |
|||
|
|||
const props = defineProps({ |
|||
orderId: Number |
|||
}) |
|||
|
|||
const dialogVisible = defineModel() |
|||
|
|||
const orderInfo = ref(null) |
|||
const getOrderInfo = async () => { |
|||
const {data} = await getThinkOrder(props.orderId) |
|||
console.log(data) |
|||
orderInfo.value = data |
|||
} |
|||
|
|||
const showPay = ref(false) |
|||
const formData = ref({ |
|||
payType: 1, |
|||
cid: null, |
|||
wechatOrder: null, |
|||
}) |
|||
|
|||
const userCard = ref([]) |
|||
const searchCard = async (value) => { |
|||
if (!value) return |
|||
const {data} = await pageCard({ |
|||
page: 1, |
|||
limit: 100, |
|||
keywords: value, |
|||
forAdmin: true |
|||
}) |
|||
userCard.value = data.list.map(item => { |
|||
const expiredTime = dayjs(item.expireTime * 1000).format('YYYY-MM-DD HH:mm:ss') |
|||
let siteList = (item.siteList && item.siteList.length) ? item.siteList.map(item => item.name).join() : null |
|||
if (siteList) siteList = ` -- ${siteList}` |
|||
item.title = `有效期:${expiredTime} -- ${item.username} -- ${item.phone} -- ${item.name}${siteList}` |
|||
return item |
|||
}) |
|||
} |
|||
|
|||
const selectUserCard = async (id) => { |
|||
const card = userCard.value.find(item => item.id === id) |
|||
if (card) { |
|||
for (const key in formData) { |
|||
formData[key] = card[key] |
|||
} |
|||
formData.wechatOrder = null |
|||
formData.payType = null |
|||
} |
|||
} |
|||
|
|||
const closePay = () => { |
|||
showPay.value = false |
|||
formData.value = { |
|||
payType: 1, |
|||
cid: null, |
|||
} |
|||
} |
|||
|
|||
const showAuthCodeInput = ref(false) |
|||
const authCode = ref('') |
|||
const authCodeInput = ref(null) |
|||
const selectPay = async () => { |
|||
if (formData.value.payType === 1) { |
|||
authCode.value = '' |
|||
showAuthCodeInput.value = true |
|||
setTimeout(() => { |
|||
nextTick(() => { |
|||
authCodeInput.value.focus() |
|||
}) |
|||
}, 0) |
|||
} else await changePayStatus() |
|||
} |
|||
|
|||
const onCodeInput = e => { |
|||
// if (e.length === 18) doPay() |
|||
} |
|||
|
|||
const disabledPay = ref(false) |
|||
const doPay = async () => { |
|||
disabledPay.value = true |
|||
const loadingInstance = ElLoading.service({fullscreen: true, text: '支付中'}) |
|||
const pay_method = parseInt(authCode.value.substring(0, 2)) < 20 ? 0 : 1 |
|||
if (pay_method === 1) { |
|||
ElMessage.error({message: '不支持支付宝'}) |
|||
disabledPay.value = false |
|||
return |
|||
} |
|||
await thinkOrderCodePay(props.orderId, {code: authCode.value}).catch(() => { |
|||
disabledPay.value = false |
|||
loadingInstance.close() |
|||
}) |
|||
await checkPayRes() |
|||
loadingInstance.close() |
|||
} |
|||
|
|||
const checkPayRes = async () => { |
|||
const loadingInstance = ElLoading.service({fullscreen: true, text: '等待用户输入支付密码'}) |
|||
const {data} = await offlinePayCheckReq(props.orderId) |
|||
if (data.state === 'SUCCESS') { |
|||
disabledPay.value = false |
|||
loadingInstance.close() |
|||
ElMessage.success({message: '支付成功'}) |
|||
setTimeout(() => { |
|||
reload() |
|||
}, 1000) |
|||
} else if (data.state === 'PAYERROR') { |
|||
disabledPay.value = false |
|||
loadingInstance.close() |
|||
ElMessage.error({message: '支付失败'}) |
|||
setTimeout(() => { |
|||
reload() |
|||
}, 1000) |
|||
} else await checkPayRes() |
|||
} |
|||
|
|||
const changePayStatus = async () => { |
|||
await updateThinkOrder({ |
|||
id: props.orderId, |
|||
payStatus: 1, |
|||
payTime: dayjs().unix(), |
|||
}) |
|||
ElMessage.success('支付成功') |
|||
reload() |
|||
} |
|||
|
|||
const disablePrint = ref(false) |
|||
const print = async () => { |
|||
disablePrint.value = true |
|||
ElLoading.service({ |
|||
lock: true, |
|||
text: '正在打印...', |
|||
background: 'rgba(0, 0, 0, 0.7)' |
|||
}) |
|||
const res = await printReq({ |
|||
orderId: props.orderId |
|||
}).catch(() => { |
|||
disablePrint.value = false |
|||
ElLoading.service().close() |
|||
}) |
|||
disablePrint.value = false |
|||
ElLoading.service().close() |
|||
console.log(res) |
|||
} |
|||
|
|||
|
|||
onMounted(() => { |
|||
getOrderInfo() |
|||
}) |
|||
|
|||
const emits = defineEmits(['close']) |
|||
|
|||
const store = reloadFlagStore() |
|||
const reload = () => { |
|||
store.setData(true) |
|||
showPay.value = false |
|||
showAuthCodeInput.value = false |
|||
dialogVisible.value = false |
|||
emits('close') |
|||
} |
|||
</script> |
@ -0,0 +1,38 @@ |
|||
<template> |
|||
<el-pagination |
|||
class="mt-4 justify-center" |
|||
background |
|||
layout="prev, pager, next, total, sizes, jumper" |
|||
@size-change="handleSizeChange" |
|||
@current-change="handleCurrentChange" |
|||
:page-size="perPage" |
|||
:page-sizes="[5, 10, 20, 50, 100, 200, 500, 1000, 2000, 5000, 10000]" |
|||
:total="total"/> |
|||
</template> |
|||
|
|||
<script setup> |
|||
defineProps({ |
|||
perPage: { |
|||
type: Number, |
|||
default: 50 |
|||
}, |
|||
total: { |
|||
type: Number, |
|||
default: 0 |
|||
}, |
|||
currentPage: { |
|||
type: Number, |
|||
default: 1 |
|||
}, |
|||
|
|||
}) |
|||
|
|||
const emits = defineEmits(['change-size', 'change-page']) |
|||
const handleSizeChange = size =>{ |
|||
emits('change-size', {size}) |
|||
} |
|||
|
|||
const handleCurrentChange = page =>{ |
|||
emits('change-page', {page}) |
|||
} |
|||
</script> |
@ -0,0 +1,229 @@ |
|||
<template> |
|||
<el-dialog |
|||
v-model="dialogVisible" |
|||
title="续卡" |
|||
width="80%" |
|||
:before-close="reload" |
|||
> |
|||
<el-form label-width="120px"> |
|||
<el-row :gutter="10"> |
|||
<el-col :span="12"> |
|||
<el-form-item label="IC卡搜索"> |
|||
<el-select size="large" v-model="selectedCard" placeholder="姓名/手机号/卡号搜索" filterable :remote-method="searchCard" |
|||
@change="selectUserCard" remote> |
|||
<el-option |
|||
v-for="item in userCard" |
|||
:key="item.id" |
|||
:label="item.title" |
|||
:value="item.id"> |
|||
</el-option> |
|||
</el-select> |
|||
</el-form-item> |
|||
<el-form-item label="IC卡名称"> |
|||
<el-input size="large" v-model="formData.name" disabled placeholder="请选择IC卡"/> |
|||
</el-form-item> |
|||
<el-form-item label="IC卡可用场馆"> |
|||
<template v-if="formData.siteList && formData.siteList.length">{{ |
|||
formData.siteList.map(item => item.name).join() |
|||
}}</template> |
|||
</el-form-item> |
|||
<el-form-item label="IC卡年限"> |
|||
<el-input size="large" v-model="formData.term" disabled placeholder="请选择IC卡"> |
|||
<template #append>年</template> |
|||
</el-input> |
|||
</el-form-item> |
|||
<el-form-item label="IC卡月限"> |
|||
<el-input size="large" v-model="formData.month" disabled placeholder="请选择IC卡"> |
|||
<template #append>月</template> |
|||
</el-input> |
|||
</el-form-item> |
|||
<el-form-item label="IC卡折扣"> |
|||
<el-input size="large" v-model="formData.discount" disabled placeholder="请选择IC卡"> |
|||
<el-input v-model="formData.term" disabled placeholder="请选择IC卡"> |
|||
<template #append>折</template> |
|||
</el-input> |
|||
</el-input> |
|||
</el-form-item> |
|||
<el-form-item label="IC卡类型"> |
|||
<el-select size="large" v-model="formData.type" placeholder="请选择VIP卡" disabled> |
|||
<el-option label="年卡" :value="1"/> |
|||
<el-option label="次卡" :value="2"/> |
|||
<el-option label="月卡" :value="3"/> |
|||
<el-option label="会员IC卡" :value="4"/> |
|||
<el-option label="充值卡" :value="5"/> |
|||
</el-select> |
|||
</el-form-item> |
|||
<el-form-item label="使用次数"> |
|||
<el-input size="large" v-model="formData.count" disabled placeholder="请选择IC卡"> |
|||
<template #append>次</template> |
|||
</el-input> |
|||
</el-form-item> |
|||
</el-col> |
|||
<el-col :span="12"> |
|||
<el-form-item label="手机号"> |
|||
<el-input size="large" v-model="formData.phone" disabled placeholder="请选择VIP卡"/> |
|||
</el-form-item> |
|||
<el-form-item label="身份证号"> |
|||
<el-input size="large" v-model="formData.idcard" disabled placeholder="请选择VIP卡"/> |
|||
</el-form-item> |
|||
<el-form-item label="用户姓名"> |
|||
<el-input size="large" v-model="formData.username" disabled placeholder="请选择VIP卡"/> |
|||
</el-form-item> |
|||
<el-form-item label="支付方式" required> |
|||
<el-select size="large" v-model="formData.payType" placeholder="请选择支付方式"> |
|||
<el-option label="微信支付" :value="1"/> |
|||
<el-option label="支付宝支付" :value="2"/> |
|||
<el-option label="现金" :value="3"/> |
|||
<el-option label="POS机刷卡" :value="4"/> |
|||
</el-select> |
|||
</el-form-item> |
|||
<el-form-item label="支付凭证" required> |
|||
<el-input size="large" v-model="formData.wechatOrder" placeholder="请输入微信支付号/支付凭证号/收据单号"/> |
|||
</el-form-item> |
|||
<el-form-item label="付款金额"> |
|||
<span v-if="formData.price" class="text-xl text-red-500">{{ formData.price }}元</span> |
|||
</el-form-item> |
|||
<el-form-item label="充值次数"> |
|||
<span v-if="formData.count" class="text-xl text-red-500">{{ formData.count }}次</span> |
|||
</el-form-item> |
|||
<el-form-item> |
|||
<el-button size="large" type="primary" :disabled="!formData.vid || !formData.payType" style="width: 100%" @click="save"> |
|||
确认充值 |
|||
</el-button> |
|||
</el-form-item> |
|||
</el-col> |
|||
</el-row> |
|||
</el-form> |
|||
<template #footer> |
|||
<div> |
|||
<el-button @click="reload">关闭</el-button> |
|||
</div> |
|||
</template> |
|||
</el-dialog> |
|||
</template> |
|||
|
|||
<script setup> |
|||
|
|||
import {onMounted, reactive, ref} from "vue"; |
|||
import {listThinkVip} from "@/api/thinkVip.js"; |
|||
import {ElMessage} from "element-plus"; |
|||
import {addThinkCard, addThinkCardLog, listThinkCard, pageCard} from "@/api/icCard.js"; |
|||
import {reloadFlagStore} from "@/store/index.js"; |
|||
import dayjs from "dayjs"; |
|||
|
|||
const dialogVisible = defineModel() |
|||
|
|||
const defaultData = { |
|||
sid: null, |
|||
uid: null, |
|||
vid: null, |
|||
aid: null, |
|||
wechatOrder: null, |
|||
code: null, |
|||
name: null, |
|||
username: null, |
|||
phone: null, |
|||
price: null, |
|||
desc: null, |
|||
info: null, |
|||
discount: null, |
|||
count: null, |
|||
eachMoney: null, |
|||
remainingMoney: null, |
|||
number: null, |
|||
num: null, |
|||
status: null, |
|||
term: null, |
|||
month: null, |
|||
type: null, |
|||
cardType: null, |
|||
vipType: null, |
|||
pic: null, |
|||
prices: null, |
|||
payType: null, |
|||
isIntegral: null, |
|||
isInvoice: null, |
|||
expireTime: null, |
|||
makeNum: null, |
|||
urgentName: null, |
|||
urgentPhone: null, |
|||
cardNum: null, |
|||
password: null, |
|||
useTime: null, |
|||
createTime: null, |
|||
idcard: null, |
|||
confirmPassword: null, |
|||
payVoucher: null, |
|||
siteList: [], |
|||
} |
|||
|
|||
let formData = reactive({...defaultData}) |
|||
|
|||
const save = async () => { |
|||
if (formData.payType !== 1 && !formData.wechatOrder) { |
|||
ElMessage.error('请输入支付凭证') |
|||
return |
|||
} |
|||
const logData = { |
|||
code: formData.code, |
|||
payType: formData.payType, |
|||
money: formData.price, |
|||
wechatOrder: formData.wechatOrder, |
|||
count: formData.count, |
|||
createTime: dayjs().unix(), |
|||
} |
|||
const res = await addThinkCardLog(logData) |
|||
if (res) { |
|||
ElMessage.success('续费成功') |
|||
formData = {...defaultData} |
|||
reload() |
|||
} |
|||
} |
|||
|
|||
const selectedCard = ref() |
|||
const userCard = ref([]) |
|||
const searchCard = async (value) => { |
|||
if (!value) return |
|||
const {data} = await pageCard({ |
|||
page:1, |
|||
limit: 100, |
|||
keywords: value, |
|||
forAdmin: true |
|||
}) |
|||
userCard.value = data.list.map(item => { |
|||
const expiredTime = dayjs(item.expireTime * 1000).format('YYYY-MM-DD HH:mm:ss') |
|||
let siteList = (item.siteList && item.siteList.length) ? item.siteList.map(item => item.name).join() : null |
|||
if (siteList) siteList = ` -- ${siteList}` |
|||
item.title = `有效期:${expiredTime} -- ${item.username} -- ${item.phone} -- ${item.name}${siteList}` |
|||
return item |
|||
}) |
|||
} |
|||
|
|||
const selectUserCard = async (id) => { |
|||
const card = userCard.value.find(item => item.id === id) |
|||
if (card) { |
|||
for (const key in formData) { |
|||
formData[key] = card[key] |
|||
} |
|||
formData.wechatOrder = null |
|||
formData.payType = null |
|||
} |
|||
} |
|||
|
|||
const vipList = ref([]) |
|||
const getVipList = async () => { |
|||
const {data} = await listThinkVip() |
|||
vipList.value = data |
|||
} |
|||
|
|||
const store = reloadFlagStore() |
|||
const reload = () => { |
|||
store.setData(true) |
|||
dialogVisible.value = false |
|||
} |
|||
|
|||
onMounted(() => { |
|||
store.setData(false) |
|||
getVipList() |
|||
}) |
|||
</script> |
@ -0,0 +1,397 @@ |
|||
<template> |
|||
<el-dialog |
|||
v-model="dialogVisible" |
|||
:title="mode === 'select' ? '场地选择' : `场地预定 -- ${siteName}`" |
|||
width="80%" |
|||
top="10px" |
|||
:before-close="reload" |
|||
:close-on-click-modal="false" |
|||
> |
|||
<div class="flex justify-start items-start flex-wrap" v-if="mode === 'select'"> |
|||
<div v-for="(item, index) in siteList" |
|||
class="w-1/4 p-2 cursor-pointer" |
|||
:key="index"> |
|||
<div style="height: 100px" |
|||
@click="selectSite(item)" |
|||
class="rounded-xl flex justify-center items-center bg-gradient-to-b from-cyan-500 to-blue-500 text-white w-full h-full"> |
|||
{{ item.name }} |
|||
</div> |
|||
</div> |
|||
</div> |
|||
<div v-else> |
|||
<div class="flex justify-start items-start flex-wrap"> |
|||
<div v-for="(item, index) in siteList" |
|||
class="p-2 cursor-pointer" |
|||
style="flex: 0 0 15%" |
|||
:key="index"> |
|||
<div style="height: 50px" |
|||
@click="selectSite(item)" |
|||
:class="[item.id === sid ? 'bg-gradient-to-b from-cyan-500 to-blue-500 text-white' : 'border']" |
|||
class="rounded-xl flex justify-center items-center w-full h-full"> |
|||
{{ item.name }} |
|||
</div> |
|||
</div> |
|||
</div> |
|||
<el-divider/> |
|||
<div class="flex justify-start items-start overflow-y-auto"> |
|||
<div v-for="(item, index) in dateList" |
|||
class="p-2 cursor-pointer" |
|||
style="flex: 0 0 10%" |
|||
:key="index"> |
|||
<div style="height: 50px" |
|||
@click="selectDate(item)" |
|||
:class="[item === date ? 'bg-gradient-to-b from-cyan-300 to-green-500 text-white' : 'border']" |
|||
class="rounded-xl flex justify-center items-center w-full h-full"> |
|||
{{ chDateStr(item) }} |
|||
</div> |
|||
</div> |
|||
</div> |
|||
<el-divider/> |
|||
<div class="flex justify-start items-start mb-2"> |
|||
<div class="flex justify-center items-center" v-if="fieldList.length && fieldList[0].isHalf === 1"> |
|||
<el-switch v-model="formData.type" active-color="#13ce66" inactive-color="#ff4949" active-text="全场" |
|||
:active-value="1" :inactive-value="2" |
|||
inactive-text="半场"></el-switch> |
|||
</div> |
|||
<div class="flex justify-center items-center mx-2"> |
|||
<span>可预约</span> |
|||
<div style="width: 30px; height: 30px " class="border ml-2"></div> |
|||
</div> |
|||
<div class="flex justify-center items-center mx-2"> |
|||
<span>选中</span> |
|||
<div style="width: 30px; height: 30px " class="border ml-2 bg-blue-400"></div> |
|||
</div> |
|||
<div class="flex justify-center items-center mx-2"> |
|||
<span>已预约半场</span> |
|||
<div style="width: 30px; height: 30px " class="border ml-2 bg-green-300"></div> |
|||
</div> |
|||
<div class="flex justify-center items-center mx-2"> |
|||
<span>已出售</span> |
|||
<div style="width: 30px; height: 30px " class="border ml-2 bg-red-400"></div> |
|||
</div> |
|||
<div class="flex justify-center items-center mx-2"> |
|||
<span>已使用</span> |
|||
<div style="width: 30px; height: 30px " class="border ml-2 bg-gray-300"></div> |
|||
</div> |
|||
</div> |
|||
<div class=" overflow-x-auto"> |
|||
<div class="flex justify-start items-start"> |
|||
<div style="height: 40px; flex: 0 0 200px" |
|||
class="flex justify-center items-center w-full h-full bg-emerald-400 text-white border sticky left-0"> |
|||
时间 |
|||
</div> |
|||
<div v-for="(item, index) in fieldList" |
|||
style="height: 40px; flex: 0 0 200px" |
|||
class="cursor-pointer" |
|||
:key="index"> |
|||
<div |
|||
class="flex justify-center items-center w-full h-full bg-emerald-400 text-white border"> |
|||
{{ item.name }} |
|||
</div> |
|||
</div> |
|||
</div> |
|||
<div class="flex justify-start items-start flex-col"> |
|||
<div v-for="(item, index) in periodList" |
|||
class="cursor-pointer flex justify-start items-start" |
|||
:key="index"> |
|||
<div |
|||
style="height: 40px; width: 200px" |
|||
@click="selectTime(item.timePeriod)" |
|||
:class="[selectedTimeList.includes(item.timePeriod) ? 'bg-cyan-300' : '']" |
|||
class="flex justify-center items-center w-full h-full border sticky left-0 bg-white"> |
|||
{{ item.timePeriod }} |
|||
</div> |
|||
<div v-for="field in fieldList" |
|||
style="height: 40px; width: 200px" |
|||
class="cursor-pointer" |
|||
:key="field.id"> |
|||
<div |
|||
@click="selectField(item, field)" |
|||
:class="[(selectedTimeList.includes(item.timePeriod)) ? 'bg-cyan-50' : '', |
|||
selectedFieldTimeList.includes(`${field.id}_${item.id}`) ? 'bg-blue-400 text-white' : '', |
|||
checkSold(item, field) ? 'bg-gray-300 text-white' : '', |
|||
checkSoldButNotUsed(item, field) ? 'bg-red-400 text-white' : '', |
|||
]" |
|||
class="flex justify-center items-center w-full h-full border"> |
|||
{{ item.price }}元 |
|||
</div> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
<template #footer> |
|||
<div class="flex justify-center items-center border-t pt-2"> |
|||
<el-button :disabled="!selectedFieldTimeList.length" type="success" size="large" @click="openConfirm" round |
|||
style="width: 200px" v-if="mode === 'site'">预定 |
|||
</el-button> |
|||
<el-button type="danger" plain size="large" @click="reload" round style="width: 200px">关闭</el-button> |
|||
</div> |
|||
</template> |
|||
</el-dialog> |
|||
<el-dialog |
|||
v-model="showConfirm" |
|||
title="场地确认" |
|||
width="60%" |
|||
top="20px" |
|||
:close-on-click-modal="false" |
|||
> |
|||
<el-form label-width="140px"> |
|||
<el-form-item label="姓名" required> |
|||
<el-input v-model="formData.name" placeholder="请输入姓名"/> |
|||
</el-form-item> |
|||
<el-form-item label="手机号码" required> |
|||
<el-input v-model="formData.phone" placeholder="请输入姓名"/> |
|||
</el-form-item> |
|||
<el-form-item label="场馆"> |
|||
<el-input v-model="formData.siteName" readonly/> |
|||
</el-form-item> |
|||
<el-form-item label="合计金额"> |
|||
<el-input v-model="formData.price" readonly/> |
|||
</el-form-item> |
|||
<el-form-item label="场地"> |
|||
<el-space direction="vertical"> |
|||
<el-button type="primary" v-for="(item, index) in selectedFieldList" :key="index">{{ item }}</el-button> |
|||
</el-space> |
|||
</el-form-item> |
|||
</el-form> |
|||
<template #footer> |
|||
<div class="flex justify-center items-center border-t pt-2"> |
|||
<el-button @click.native="action(-1)" type="primary" plain size="large" round |
|||
:disabled="!formData.name || !formData.phone" |
|||
style="width: 200px">确认预定(暂不支付) |
|||
</el-button> |
|||
<el-button @click.native="action(3)" type="success" :disabled="!formData.name || !formData.phone" size="large" |
|||
round style="width: 200px"> |
|||
确认预定并支付 |
|||
</el-button> |
|||
</div> |
|||
</template> |
|||
</el-dialog> |
|||
<OrderInfo v-model="showInfo" v-if="showInfo" :order-id="orderId" @close="getFieldList"></OrderInfo> |
|||
</template> |
|||
|
|||
<script setup> |
|||
|
|||
import {onMounted, reactive, ref} from "vue"; |
|||
import {listThinkSite, listThinkSiteTime} from "@/api/site.js"; |
|||
import {reloadFlagStore} from "@/store/index.js"; |
|||
import dayjs from "dayjs"; |
|||
import {listThinkFieldWithTimeList} from "@/api/field.js"; |
|||
import {ElMessage} from "element-plus"; |
|||
import {addThinkOrder} from "@/api/order.js"; |
|||
import OrderInfo from "@/components/OrderInfo.vue"; |
|||
|
|||
const siteList = ref([]) |
|||
const getSiteList = async () => { |
|||
const {data} = await listThinkSite() |
|||
siteList.value = data |
|||
} |
|||
|
|||
const chDateStr = (date) => { |
|||
const week = ['日', '一', '二', '三', '四', '五', '六'] |
|||
return `${date} 星期${week[dayjs(date).day()]}` |
|||
} |
|||
|
|||
const dateList = ref([]) |
|||
const date = ref() |
|||
const week = ref() |
|||
const setDateList = async () => { |
|||
const dayNum = 180 |
|||
dateList.value = [] |
|||
for (let i = 0; i < dayNum; i++) { |
|||
dateList.value.push(dayjs().add(i, 'day').format('YYYY-MM-DD')) |
|||
} |
|||
selectDate(dateList.value[0]) |
|||
} |
|||
|
|||
const selectDate = (item) => { |
|||
date.value = item |
|||
week.value = dayjs(item).format('d') === '0' ? '7' : dayjs().format('d') |
|||
makeTimeList() |
|||
} |
|||
|
|||
const dialogVisible = defineModel() |
|||
const mode = ref('select') |
|||
const sid = ref(null) |
|||
const siteName = ref('') |
|||
|
|||
const selectSite = (item) => { |
|||
sid.value = item.id |
|||
siteName.value = item.name |
|||
mode.value = 'site' |
|||
getSiteTimeList() |
|||
} |
|||
|
|||
|
|||
const siteTimeList = ref([]) |
|||
const getSiteTimeList = async () => { |
|||
const {data} = await listThinkSiteTime({ |
|||
sid: sid.value, |
|||
date: date.value |
|||
}) |
|||
siteTimeList.value = data |
|||
siteTimeList.value = siteTimeList.value.filter(item => { |
|||
return JSON.parse(item.week).map(Number).includes(parseInt(week.value)) |
|||
}) |
|||
makeTimeList() |
|||
} |
|||
|
|||
const periodList = ref([]) |
|||
const makeTimeList = () => { |
|||
periodList.value = [] |
|||
selectedTimeList.value = [] |
|||
selectedFieldTimeList.value = [] |
|||
siteTimeList.value.forEach(item => { |
|||
const weekList = JSON.parse(item.week) |
|||
if (parseInt(sid.value) === 37) { |
|||
const today = dayjs().format('YYYY-MM-DD') |
|||
if (dayjs().isBefore(dayjs(today + ' 21:00:00'))) periodList.value.push(item) |
|||
} else { |
|||
if (weekList.includes(week.value)) periodList.value.push(item) |
|||
} |
|||
}) |
|||
// console.log(periodList.value) |
|||
getFieldList() |
|||
} |
|||
|
|||
const fidList = ref([]) |
|||
const fieldList = ref([]) |
|||
const getFieldList = async () => { |
|||
if (!periodList.value.length) return |
|||
const periodVoList = [] |
|||
periodList.value.forEach(item => { |
|||
const timestamp = dayjs(date.value + ' ' + item.timePeriod.split(' - ')[0]).unix() |
|||
periodVoList.push({ |
|||
timestamp, |
|||
period: item.timePeriod, |
|||
id: item.id |
|||
}) |
|||
}) |
|||
const res = await listThinkFieldWithTimeList({ |
|||
sid: sid.value, |
|||
periodVoList |
|||
}) |
|||
if (res) fieldList.value = res.data |
|||
console.log(fieldList.value) |
|||
console.log(periodList.value) |
|||
} |
|||
|
|||
const selectedTimeList = ref([]) |
|||
const selectTime = (item) => { |
|||
if (selectedTimeList.value.includes(item)) { |
|||
selectedTimeList.value = selectedTimeList.value.filter(i => i !== item) |
|||
} else { |
|||
selectedTimeList.value.push(item) |
|||
} |
|||
} |
|||
|
|||
const selectedFieldTimeList = ref([]) |
|||
const selectField = (time, field) => { |
|||
const period = field.periodVoList.find(item => item.id === time.id) |
|||
if (sid.value === 37) { |
|||
const today = dayjs().format('YYYY-MM-DD') |
|||
if (dayjs().isAfter(dayjs(today + ' 21:00:00'))) return ElMessage.error('已超时,无法订场'); |
|||
} else { |
|||
if (dayjs().unix() > period.timestamp) return ElMessage.error('已超时,无法订场'); |
|||
} |
|||
if (period.sold || period.took) return |
|||
const item = `${field.id}_${time.id}` |
|||
if (selectedFieldTimeList.value.includes(item)) { |
|||
selectedFieldTimeList.value = selectedFieldTimeList.value.filter(i => i !== item) |
|||
} else { |
|||
selectedFieldTimeList.value.push(item) |
|||
} |
|||
} |
|||
|
|||
const checkSold = (time, field) => { |
|||
const item = field.periodVoList.find(item => item.id === time.id) |
|||
if (item) return item.sold |
|||
return false |
|||
} |
|||
|
|||
const checkSoldButNotUsed = (time, field) => { |
|||
const item = field.periodVoList.find(item => item.id === time.id) |
|||
if (item) return item.took |
|||
return false |
|||
} |
|||
|
|||
const selectedFieldList = ref([]) |
|||
const showConfirm = ref(false) |
|||
const openConfirm = () => { |
|||
showConfirm.value = true |
|||
selectedFieldList.value = [] |
|||
formData.price = selectedFieldTimeList.value.map(item => { |
|||
const [fid, tid] = item.split('_') |
|||
const field = fieldList.value.find(i => i.id === parseInt(fid)) |
|||
const period = periodList.value.find(i => i.id === parseInt(tid)) |
|||
selectedFieldList.value.push(`${date.value} ${period.timePeriod} ${field.name}`) |
|||
return period.price |
|||
}).reduce((a, b) => a + b, 0) |
|||
const site = siteList.value.find(item => item.id === parseInt(sid.value)) |
|||
formData.siteName = site.name |
|||
formData.sid = site.id |
|||
} |
|||
|
|||
const formData = reactive({ |
|||
name: '', |
|||
phone: '', |
|||
siteName: '', |
|||
price: '', |
|||
sid: '', |
|||
type: 1, |
|||
payType: 0, |
|||
isChildren: 2, |
|||
thinkOrderInfos: [] |
|||
}) |
|||
|
|||
|
|||
const showInfo = ref(false) |
|||
const orderId = ref() |
|||
const action = async (payStatus) => { |
|||
formData.thinkOrderInfos = [] |
|||
let formStartTime = '' |
|||
selectedFieldTimeList.value.forEach((item, index) => { |
|||
const [fid, tid] = item.split('_') |
|||
const field = fieldList.value.find(i => i.id === parseInt(fid)) |
|||
const period = periodList.value.find(i => i.id === parseInt(tid)) |
|||
const [start, end] = period.timePeriod.split(' - ') |
|||
let startTime = dayjs(`${date.value} ${start}:00`).unix() |
|||
if (index === 0) formStartTime = startTime |
|||
formData.thinkOrderInfos.push({ |
|||
sid: formData.sid, |
|||
fid, |
|||
siteTimeId: tid, |
|||
siteName: formData.siteName, |
|||
fieldName: field.name, |
|||
dateTime: `${date.value}(${chDateStr(date.value).split(' ')[1]})${period.timePeriod}`, |
|||
payStatus: 3, |
|||
type: formData.type, |
|||
mergeData: `${date.value}${start}${end}${formData.sid}${fid}`, |
|||
startTime, |
|||
isChildren: formData.isChildren, |
|||
adultNum: 1, |
|||
childrenNum: 0, |
|||
}) |
|||
}) |
|||
formData.startTime = formStartTime |
|||
formData.payStatus = 3 |
|||
const {data} = await addThinkOrder(formData) |
|||
orderId.value = data |
|||
showConfirm.value = false |
|||
showInfo.value = true |
|||
selectedFieldTimeList.value = [] |
|||
selectedTimeList.value = [] |
|||
} |
|||
|
|||
const store = reloadFlagStore() |
|||
const reload = () => { |
|||
store.setData(true) |
|||
dialogVisible.value = false |
|||
} |
|||
|
|||
onMounted(() => { |
|||
getSiteList() |
|||
setDateList() |
|||
}) |
|||
</script> |
@ -0,0 +1,11 @@ |
|||
const hostUrl = 'https://gxtyzx-api2.websoft.top/api' |
|||
|
|||
export default { |
|||
define: { |
|||
'process.env': { |
|||
'VUE_APP_SERVER_API': 'https://gxtyzx-server.websoft.top/api', |
|||
'VUE_APP_RESOURCE_URL': hostUrl, |
|||
'VUE_APP_BASE_API': hostUrl, |
|||
} |
|||
} |
|||
} |
@ -0,0 +1,14 @@ |
|||
const hostUrl = 'https://gxtyzx-api2.websoft.top/api' |
|||
// const hostUrl = 'http://localhost:9099/api'
|
|||
|
|||
|
|||
export default { |
|||
define: { |
|||
'process.env': { |
|||
'VUE_APP_SERVER_API': 'https://gxtyzx-server.websoft.top/api', |
|||
'VUE_APP_RESOURCE_URL': hostUrl, |
|||
'VUE_APP_BASE_API': hostUrl, |
|||
} |
|||
} |
|||
} |
|||
export {hostUrl} |
@ -0,0 +1,25 @@ |
|||
import {createApp} from 'vue' |
|||
import App from './App.vue' |
|||
import './style.css' |
|||
|
|||
import ElementPlus from 'element-plus' |
|||
import zhCn from 'element-plus/dist/locale/zh-cn.mjs' |
|||
import 'element-plus/dist/index.css' |
|||
import * as ElementPlusIconsVue from '@element-plus/icons-vue' |
|||
import Page from './components/Page.vue' |
|||
import { createPinia } from 'pinia' |
|||
|
|||
import router from './router' |
|||
|
|||
const app = createApp(App) |
|||
|
|||
app.use(ElementPlus, {locale: zhCn}).use(router).component('page', Page) |
|||
|
|||
const pinia = createPinia() |
|||
app.use(pinia) |
|||
for (const [key, component] of Object.entries(ElementPlusIconsVue)) { |
|||
app.component(key, component) |
|||
} |
|||
|
|||
|
|||
app.mount('#app') |
@ -0,0 +1,118 @@ |
|||
<template> |
|||
<div class="w-full"> |
|||
<div class=" m-6 rounded-xl"> |
|||
<div class="p-3 w-full bg-white rounded-xl"> |
|||
<el-space alignment="flex-end"> |
|||
<div class="flex flex-col justify-start items-start"> |
|||
<span class="text-sm text-gray-500">物品名称</span> |
|||
<el-input size="large" style="width: 300px" v-model="keywords" placeholder="物品名称筛选" |
|||
@keyup.enter.native="getList(true)" |
|||
clearable/> |
|||
</div> |
|||
<div class="flex flex-col justify-start items-start"> |
|||
<span class="text-sm text-gray-500">下单时间</span> |
|||
<el-date-picker size="large" v-model="createTimeRange" type="daterange" placeholder="下单时间筛选"></el-date-picker> |
|||
</div> |
|||
<el-button size="large" icon="Search" @click.native="getList(true)" type="primary"> |
|||
搜索 |
|||
</el-button> |
|||
<el-button size="large" icon="RefreshRight" @click.native="init" type="warning" |
|||
margin-left="mx-4">重置 |
|||
</el-button> |
|||
</el-space> |
|||
</div> |
|||
<div class="p-3 w-full rounded-xl mt-4 bg-white"> |
|||
<el-table size="large" :data="list" stripe v-loading="loading" :height="tableHeight"> |
|||
<el-table-column prop="money" label="押金"/> |
|||
<el-table-column prop="info" label="抵押物名称"/> |
|||
<el-table-column label="押金类型" v-slot="scope"> |
|||
<span v-if="scope.row.type === 1">收取押金</span> |
|||
<span v-if="scope.row.type === 2">退押金</span> |
|||
</el-table-column> |
|||
<el-table-column prop="siteName" label="场馆名称"/> |
|||
<el-table-column label="支付方式" v-slot="scope"> |
|||
<el-tag v-if="scope.row.moneyType === 1" type="success"> |
|||
微信支付 |
|||
</el-tag> |
|||
<el-tag v-if="scope.row.moneyType === 2"> |
|||
支付宝 |
|||
</el-tag> |
|||
<el-tag v-if="scope.row.moneyType === 3"> |
|||
现金 |
|||
</el-tag> |
|||
<el-tag v-if="scope.row.moneyType === 4"> |
|||
POS机 |
|||
</el-tag> |
|||
</el-table-column> |
|||
<el-table-column label="押金状态" v-slot="scope"> |
|||
<span class="text-green-500" v-if="scope.row.status === 1">已付</span> |
|||
<span class="text-blue-500" v-if="scope.row.status === 2">已退</span> |
|||
<span class="text-gray-300" v-if="scope.row.status === 0">未付</span> |
|||
</el-table-column> |
|||
<el-table-column label="支付时间" v-slot="scope"> |
|||
<div>{{ dayjs(scope.row.createTime * 1000).format('YYYY-MM-DD HH:mm:ss') }}</div> |
|||
</el-table-column> |
|||
</el-table> |
|||
|
|||
<page :per-page="perPage" :current-page="currentPage" :total="total" @change-size="changeSize" |
|||
@change-page="changePage"/> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
</template> |
|||
|
|||
<script setup> |
|||
import {onMounted, ref} from 'vue' |
|||
import dayjs from "dayjs"; |
|||
import {pageDeposit} from "@/api/deposit.js"; |
|||
|
|||
const list = ref([]) |
|||
const loading = ref(true) |
|||
const perPage = ref(20) |
|||
const total = ref(0) |
|||
const currentPage = ref(1) |
|||
|
|||
const changeSize = ({size}) => { |
|||
perPage.value = size |
|||
getList(true) |
|||
} |
|||
|
|||
const changePage = ({page}) => { |
|||
currentPage.value = page |
|||
getList() |
|||
} |
|||
|
|||
const keywords = ref('') |
|||
const payType = ref(null) |
|||
const createTimeRange = ref([]) |
|||
const getList = async (reload = false) => { |
|||
let createTimeStart = null, createTimeEnd = null, orderTimeStart = null, orderTimeEnd = null |
|||
if (reload) { |
|||
currentPage.value = 1 |
|||
loading.value = true |
|||
} |
|||
loading.value = true |
|||
if (createTimeRange.value && createTimeRange.value.length) { |
|||
createTimeStart = dayjs(createTimeRange.value[0]).unix() |
|||
createTimeEnd = dayjs(createTimeRange.value[1] + ' 23:59:59').unix() |
|||
} |
|||
|
|||
const res = await pageDeposit({ |
|||
page: currentPage.value, |
|||
limit: perPage.value, |
|||
keywords: keywords.value ?? null, |
|||
createTimeStart: createTimeStart ?? null, |
|||
createTimeEnd: createTimeEnd ?? null, |
|||
forAdmin: true |
|||
}) |
|||
loading.value = false |
|||
total.value = res.data.count |
|||
list.value = res.data.list |
|||
} |
|||
|
|||
const tableHeight = ref(1080) |
|||
onMounted(async () => { |
|||
tableHeight.value = document.body.clientHeight - 260 |
|||
await getList() |
|||
}) |
|||
</script> |
@ -0,0 +1,142 @@ |
|||
<template> |
|||
<div class="w-full"> |
|||
<div class=" m-6 rounded-xl"> |
|||
<div class="p-3 w-full bg-white rounded-xl"> |
|||
<el-space alignment="flex-end"> |
|||
<div class="flex flex-col justify-start items-start"> |
|||
<span class="text-sm text-gray-500">关键词</span> |
|||
<el-input size="large" style="width: 300px" v-model="keywords" placeholder="姓名/手机号/身份证/IC卡号筛选" |
|||
@keyup.enter.native="getList(true)" |
|||
clearable/> |
|||
</div> |
|||
<div class="flex flex-col justify-start items-start"> |
|||
<span class="text-sm text-gray-500">开卡时间</span> |
|||
<el-date-picker size="large" v-model="createTimeRange" type="daterange" placeholder="开卡时间筛选"></el-date-picker> |
|||
</div> |
|||
<el-button size="large" icon="Search" @click.native="getList(true)" type="primary"> |
|||
搜索 |
|||
</el-button> |
|||
<el-button size="large" icon="RefreshRight" @click.native="init" type="warning" |
|||
margin-left="mx-4">重置 |
|||
</el-button> |
|||
</el-space> |
|||
</div> |
|||
<div class="p-3 w-full rounded-xl mt-4 bg-white"> |
|||
<el-table size="large" :data="list" stripe v-loading="loading" :height="tableHeight" @row-click="openInfo"> |
|||
<el-table-column prop="id" label="IC卡号" fixed width="100"/> |
|||
<el-table-column prop="code" label="IC卡编号" width="130"/> |
|||
<el-table-column label="用户" v-slot="scope" width="130"> |
|||
<div>{{ scope.row.username }}</div> |
|||
<div>{{ scope.row.phone }}</div> |
|||
</el-table-column> |
|||
<el-table-column prop="name" label="卡名称" width="160"/> |
|||
<el-table-column prop="name" label="卡类型" v-slot="scope"> |
|||
<el-tag v-if="scope.row.type === 1">年卡</el-tag> |
|||
<el-tag v-if="scope.row.type === 2">次卡</el-tag> |
|||
<el-tag v-if="scope.row.type === 3">月卡</el-tag> |
|||
<el-tag v-if="scope.row.type === 4">会员IC卡</el-tag> |
|||
<el-tag v-if="scope.row.type === 5">充值卡</el-tag> |
|||
</el-table-column> |
|||
<el-table-column prop="remainingMoney" label="余额"/> |
|||
<el-table-column prop="price" label="购买价格"/> |
|||
<el-table-column prop="num" label="剩余次数"/> |
|||
<el-table-column prop="count" label="总次数"/> |
|||
<el-table-column prop="discount" label="折扣"/> |
|||
<el-table-column prop="month" label="月限"/> |
|||
<el-table-column prop="term" label="年限"/> |
|||
<el-table-column label="付款方式" v-slot="scope" width="100"> |
|||
<el-tag type="success" v-if="scope.row.payType === 1">微信支付</el-tag> |
|||
<el-tag type="success" v-if="scope.row.payType === 2">支付宝支付</el-tag> |
|||
<el-tag type="success" v-if="scope.row.payType === 3">现金</el-tag> |
|||
<el-tag type="success" v-if="scope.row.payType === 4">POS机刷卡</el-tag> |
|||
<el-tag type="success" v-if="scope.row.payType === 5">平安健康卡</el-tag> |
|||
</el-table-column> |
|||
<el-table-column label="支付状态" v-slot="scope"> |
|||
<span class="text-green-500" v-if="scope.row.status === 1">已支付</span> |
|||
<span class="text-red-500" v-if="scope.row.status === 2">未支付</span> |
|||
</el-table-column> |
|||
<el-table-column label="时间" v-slot="scope" width="300"> |
|||
<div>开卡时间:{{ dayjs(scope.row.createTime * 1000).format('YYYY-MM-DD HH:mm:ss') }}</div> |
|||
<div class="text-blue-500"> |
|||
过期时间:{{ dayjs(scope.row.expireTime * 1000).format('YYYY-MM-DD HH:mm:ss') }} |
|||
</div> |
|||
</el-table-column> |
|||
<el-table-column prop="remark" label="备注"/> |
|||
</el-table> |
|||
|
|||
<page :per-page="perPage" :current-page="currentPage" :total="total" @change-size="changeSize" |
|||
@change-page="changePage"/> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
<IcCardInfo v-model="showInfo" v-if="showInfo" :id="clickedId"/> |
|||
</template> |
|||
|
|||
<script setup> |
|||
import {onMounted, ref, watch} from 'vue' |
|||
import dayjs from "dayjs"; |
|||
import {pageCard} from "@/api/icCard.js"; |
|||
import {reloadFlagStore} from "@/store/index.js"; |
|||
import IcCardInfo from "@/components/IcCardInfo.vue"; |
|||
|
|||
const list = ref([]) |
|||
const loading = ref(true) |
|||
const perPage = ref(20) |
|||
const total = ref(0) |
|||
const currentPage = ref(1) |
|||
|
|||
const changeSize = ({size}) => { |
|||
perPage.value = size |
|||
getList(true) |
|||
} |
|||
|
|||
const changePage = ({page}) => { |
|||
currentPage.value = page |
|||
getList() |
|||
} |
|||
|
|||
const keywords = ref('') |
|||
const createTimeRange = ref([]) |
|||
const getList = async (reload = false) => { |
|||
let createTimeStart = null, createTimeEnd = null, orderTimeStart = null, orderTimeEnd = null |
|||
if (reload) { |
|||
currentPage.value = 1 |
|||
loading.value = true |
|||
} |
|||
loading.value = true |
|||
if (createTimeRange.value && createTimeRange.value.length) { |
|||
createTimeStart = dayjs(createTimeRange.value[0]).unix() |
|||
createTimeEnd = dayjs(createTimeRange.value[1] + ' 23:59:59').unix() |
|||
} |
|||
const res = await pageCard({ |
|||
page: currentPage.value, |
|||
limit: perPage.value, |
|||
keywords: keywords.value ?? null, |
|||
createTimeStart: createTimeStart ?? null, |
|||
createTimeEnd: createTimeEnd ?? null, |
|||
forAdmin: true, |
|||
}) |
|||
loading.value = false |
|||
total.value = res.data.count |
|||
list.value = res.data.list |
|||
} |
|||
|
|||
const showInfo = ref(false) |
|||
const clickedId = ref() |
|||
const openInfo = row => { |
|||
clickedId.value = row.id |
|||
console.log(clickedId.value) |
|||
showInfo.value = true |
|||
} |
|||
|
|||
const tableHeight = ref(1080) |
|||
onMounted(async () => { |
|||
tableHeight.value = document.body.clientHeight - 260 |
|||
await getList() |
|||
}) |
|||
|
|||
const store = reloadFlagStore() |
|||
store.$subscribe(mutation => { |
|||
if (mutation.events.newValue) getList(true) |
|||
}) |
|||
</script> |
@ -0,0 +1,237 @@ |
|||
<template> |
|||
<div class="w-full"> |
|||
<div class=" m-6 rounded-xl"> |
|||
<div class="p-3 w-full bg-white rounded-xl"> |
|||
<el-space alignment="flex-end"> |
|||
<div class="flex flex-col justify-start items-start"> |
|||
<span class="text-sm text-gray-500">关键词</span> |
|||
<el-input size="large" style="width: 300px" v-model="keywords" placeholder="姓名/手机号/订单号/IC卡号筛选" |
|||
@keyup.enter.native="getList(true)" |
|||
clearable/> |
|||
</div> |
|||
<div class="flex flex-col justify-start items-start"> |
|||
<span class="text-sm text-gray-500">支付方式</span> |
|||
<el-select size="large" v-model="payType" placeholder="支付方式筛选" style="width: 160px;" clearable> |
|||
<el-option :value="1" label="微信支付"/> |
|||
<el-option :value="2" label="余额支付"/> |
|||
<el-option :value="3" label="支付宝"/> |
|||
<el-option :value="4" label="现金"/> |
|||
<el-option :value="5" label="POS机"/> |
|||
<el-option :value="6" label="VIP月卡"/> |
|||
<el-option :value="7" label="VIP年卡"/> |
|||
<el-option :value="8" label="VIP次卡"/> |
|||
<el-option :value="9" label="IC月卡"/> |
|||
<el-option :value="10" label="IC年卡"/> |
|||
<el-option :value="11" label="IC次卡"/> |
|||
<el-option :value="12" label="免费"/> |
|||
<el-option :value="13" label="VIP充值卡"/> |
|||
<el-option :value="14" label="IC充值卡"/> |
|||
<el-option :value="15" label="积分支付"/> |
|||
<el-option :value="16" label="VIP季卡"/> |
|||
<el-option :value="17" label="IC季卡"/> |
|||
</el-select> |
|||
</div> |
|||
<div class="flex flex-col justify-start items-start"> |
|||
<span class="text-sm text-gray-500">下单时间</span> |
|||
<el-date-picker size="large" v-model="createTimeRange" type="daterange" placeholder="下单时间筛选"></el-date-picker> |
|||
</div> |
|||
<div class="flex flex-col justify-start items-start"> |
|||
<span class="text-sm text-gray-500">使用场地时间</span> |
|||
<el-date-picker size="large" v-model="orderTimeRange" type="daterange" placeholder="使用场地时间筛选"></el-date-picker> |
|||
</div> |
|||
<el-button size="large" icon="Search" @click.native="getList(true)" type="primary"> |
|||
搜索 |
|||
</el-button> |
|||
<el-button size="large" icon="RefreshRight" @click.native="init" type="warning" |
|||
margin-left="mx-4">重置 |
|||
</el-button> |
|||
</el-space> |
|||
</div> |
|||
<div class="p-3 w-full rounded-xl mt-4 bg-white"> |
|||
<el-table size="large" :data="list" stripe v-loading="loading" :height="tableHeight" @row-dblclick="openInfo"> |
|||
<el-table-column prop="orderNum" label="订单号" fixed width="200"/> |
|||
<el-table-column prop="title" label="场地名称" v-slot="scope" fixed width="280"> |
|||
<div>{{ scope.row.siteName }}</div> |
|||
<div>{{ scope.row.dateTime }}</div> |
|||
<div>¥{{ scope.row.totalPrice }}元</div> |
|||
</el-table-column> |
|||
<el-table-column prop="code" label="IC卡号"/> |
|||
<el-table-column label="用户" v-slot="scope"> |
|||
<div>{{ scope.row.name }}</div> |
|||
<div>{{ scope.row.phone }}</div> |
|||
</el-table-column> |
|||
<el-table-column label="订单金额" v-slot="scope"> |
|||
<div>¥{{ scope.row.totalPrice }}</div> |
|||
</el-table-column> |
|||
<el-table-column label="实付金额" v-slot="scope"> |
|||
<div>¥{{ scope.row.payPrice }}</div> |
|||
</el-table-column> |
|||
<el-table-column label="支付方式" v-slot="scope"> |
|||
<!-- <el-tag v-if="scope.row.payType === 0">余额支付</el-tag>--> |
|||
<el-tag v-if="scope.row.payType === 1" type="success"> |
|||
微信支付 |
|||
</el-tag> |
|||
<el-tag v-if="scope.row.payType === 2">积分</el-tag> |
|||
<el-tag v-if="scope.row.payType === 3"> |
|||
支付宝 |
|||
</el-tag> |
|||
<el-tag v-if="scope.row.payType === 4"> |
|||
现金 |
|||
</el-tag> |
|||
<el-tag v-if="scope.row.payType === 5"> |
|||
POS机 |
|||
</el-tag> |
|||
<el-tag v-if="scope.row.payType === 6" type="warning"> |
|||
VIP月卡 |
|||
</el-tag> |
|||
<el-tag v-if="scope.row.payType === 7" type="warning"> |
|||
VIP年卡 |
|||
</el-tag> |
|||
<el-tag v-if="scope.row.payType === 8" type="warning"> |
|||
VIP次卡 |
|||
</el-tag> |
|||
<el-tag v-if="scope.row.payType === 9" type="danger"> |
|||
IC月卡 |
|||
</el-tag> |
|||
<el-tag v-if="scope.row.payType === 10" type="danger"> |
|||
IC年卡 |
|||
</el-tag> |
|||
<el-tag v-if="scope.row.payType === 11" type="danger"> |
|||
IC次卡 |
|||
</el-tag> |
|||
<el-tag v-if="scope.row.payType === 12"> |
|||
免费 |
|||
</el-tag> |
|||
<el-tag v-if="scope.row.payType === 13" type="warning"> |
|||
VIP充值卡 |
|||
</el-tag> |
|||
<el-tag v-if="scope.row.payType === 14" type="danger"> |
|||
IC充值卡 |
|||
</el-tag> |
|||
<el-tag v-if="scope.row.payType === 15"> |
|||
积分支付 |
|||
</el-tag> |
|||
<el-tag v-if="scope.row.payType === 16" type="warning"> |
|||
VIP季卡 |
|||
</el-tag> |
|||
<el-tag v-if="scope.row.payType === 17" type="danger"> |
|||
IC季卡 |
|||
</el-tag> |
|||
</el-table-column> |
|||
<el-table-column label="支付状态" v-slot="scope"> |
|||
<span class="text-green-500" v-if="scope.row.payStatus === 1">已支付</span> |
|||
<span class="text-red-500" v-if="scope.row.payStatus === 2">未支付</span> |
|||
<span v-if="scope.row.payStatus === 0 || scope.row.payStatus === 3">未付款,占场中</span> |
|||
</el-table-column> |
|||
<el-table-column label="订单状态" v-slot="scope"> |
|||
<span v-if="scope.row.orderStatus === 1" class="text-green-500" |
|||
>已完成</span> |
|||
<span v-if="scope.row.orderStatus === 2" class="ele-text-placeholder" |
|||
>未使用</span> |
|||
<span v-if="scope.row.orderStatus === 3" class="text-gray-400" |
|||
>已取消</span> |
|||
<span v-if="scope.row.orderStatus === 4" class="ele-text-warning" |
|||
>退款申请中</span> |
|||
<span v-if="scope.row.orderStatus === 5">退款被拒绝</span> |
|||
<span v-if="scope.row.orderStatus === 6">退款成功</span> |
|||
<span v-if="scope.row.orderStatus === 7">客户端申请退款</span> |
|||
<span v-if="scope.row.orderStatus === 9">未完成</span> |
|||
</el-table-column> |
|||
<el-table-column label="时间" v-slot="scope" width="300"> |
|||
<div>下单时间:{{ dayjs(scope.row.createTime * 1000).format('YYYY-MM-DD HH:mm:ss') }}</div> |
|||
<div class="text-green-500">更新时间:{{ |
|||
dayjs(scope.row.updateTime * 1000).format('YYYY-MM-DD HH:mm:ss') |
|||
}} |
|||
</div> |
|||
<div class="text-blue-500" v-if="scope.row.payTime"> |
|||
支付时间:{{ dayjs(scope.row.payTime * 1000).format('YYYY-MM-DD HH:mm:ss') }} |
|||
</div> |
|||
</el-table-column> |
|||
<el-table-column label="操作"> |
|||
<template v-slot="scope"> |
|||
<el-button type="text" @click="openInfo(scope.row)">详情</el-button> |
|||
</template> |
|||
</el-table-column> |
|||
</el-table> |
|||
|
|||
<page :per-page="perPage" :current-page="currentPage" :total="total" @change-size="changeSize" |
|||
@change-page="changePage"/> |
|||
</div> |
|||
</div> |
|||
<OrderInfo v-model="showInfo" v-if="showInfo" :order-id="orderId" @close="getList(true)"></OrderInfo> |
|||
</div> |
|||
</template> |
|||
|
|||
<script setup> |
|||
import {onMounted, ref} from 'vue' |
|||
import {pageOrder} from "@/api/order.js"; |
|||
import dayjs from "dayjs"; |
|||
import OrderInfo from "@/components/OrderInfo.vue"; |
|||
|
|||
const list = ref([]) |
|||
const loading = ref(true) |
|||
const perPage = ref(20) |
|||
const total = ref(0) |
|||
const currentPage = ref(1) |
|||
|
|||
const changeSize = ({size}) => { |
|||
perPage.value = size |
|||
getList(true) |
|||
} |
|||
|
|||
const changePage = ({page}) => { |
|||
currentPage.value = page |
|||
getList() |
|||
} |
|||
|
|||
const keywords = ref('') |
|||
const payType = ref(null) |
|||
const createTimeRange = ref([]) |
|||
const orderTimeRange = ref([]) |
|||
const getList = async (reload = false) => { |
|||
let createTimeStart = null, createTimeEnd = null, orderTimeStart = null, orderTimeEnd = null |
|||
if (reload) { |
|||
currentPage.value = 1 |
|||
loading.value = true |
|||
} |
|||
loading.value = true |
|||
if (createTimeRange.value && createTimeRange.value.length) { |
|||
createTimeStart = dayjs(createTimeRange.value[0]).unix() |
|||
createTimeEnd = dayjs(createTimeRange.value[1] + ' 23:59:59').unix() |
|||
} |
|||
console.log(orderTimeRange.value) |
|||
console.log(dayjs(orderTimeRange.value[1] + ' 23:59:59').unix()) |
|||
if (orderTimeRange.value && orderTimeRange.value.length) { |
|||
orderTimeStart = dayjs(orderTimeRange.value[0]).unix() |
|||
orderTimeEnd = dayjs(orderTimeRange.value[1] + ' 23:59:59').unix() |
|||
} |
|||
const res = await pageOrder({ |
|||
page: currentPage.value, |
|||
limit: perPage.value, |
|||
keywords: keywords.value ?? null, |
|||
payType: payType.value ?? null, |
|||
createTimeStart: createTimeStart ?? null, |
|||
createTimeEnd: createTimeEnd ?? null, |
|||
orderTimeStart: orderTimeStart ?? null, |
|||
orderTimeEnd: orderTimeEnd ?? null, |
|||
forAdmin: true |
|||
}) |
|||
loading.value = false |
|||
total.value = res.data.count |
|||
list.value = res.data.list |
|||
} |
|||
|
|||
const showInfo = ref(false) |
|||
const orderId = ref() |
|||
const openInfo = (row) => { |
|||
console.log(row) |
|||
orderId.value = row.id |
|||
showInfo.value = true |
|||
} |
|||
|
|||
const tableHeight = ref(1080) |
|||
onMounted(async () => { |
|||
tableHeight.value = document.body.clientHeight - 260 |
|||
await getList() |
|||
}) |
|||
</script> |
@ -0,0 +1,130 @@ |
|||
<template> |
|||
<div class="w-full"> |
|||
<div class=" m-6 rounded-xl"> |
|||
<div class="p-3 w-full bg-white rounded-xl"> |
|||
<el-space alignment="flex-end"> |
|||
<div class="flex flex-col justify-start items-start"> |
|||
<span class="text-sm text-gray-500">关键词</span> |
|||
<el-input size="large" style="width: 300px" v-model="keywords" placeholder="姓名/手机号/身份证/IC卡号筛选" |
|||
@keyup.enter.native="getList(true)" |
|||
clearable/> |
|||
</div> |
|||
<div class="flex flex-col justify-start items-start"> |
|||
<span class="text-sm text-gray-500">开卡时间</span> |
|||
<el-date-picker size="large" v-model="createTimeRange" type="daterange" placeholder="开卡时间筛选"></el-date-picker> |
|||
</div> |
|||
<el-button size="large" icon="Search" @click.native="getList(true)" type="primary"> |
|||
搜索 |
|||
</el-button> |
|||
<el-button size="large" icon="RefreshRight" @click.native="init" type="warning" |
|||
margin-left="mx-4">重置 |
|||
</el-button> |
|||
</el-space> |
|||
</div> |
|||
<div class="p-3 w-full rounded-xl mt-4 bg-white"> |
|||
<el-table :data="list" stripe v-loading="loading" :height="tableHeight" size="large"> |
|||
<el-table-column prop="id" label="IC卡号"/> |
|||
<el-table-column prop="code" label="IC卡编号"/> |
|||
<el-table-column label="用户" v-slot="scope"> |
|||
<div>{{ scope.row.username }}</div> |
|||
<div>{{ scope.row.phone }}</div> |
|||
</el-table-column> |
|||
<el-table-column prop="name" label="卡名称"/> |
|||
<el-table-column prop="number" label="续卡次数"/> |
|||
<el-table-column prop="name" label="卡类型" v-slot="scope"> |
|||
<el-tag v-if="scope.row.type === 1">年卡</el-tag> |
|||
<el-tag v-if="scope.row.type === 2">次卡</el-tag> |
|||
<el-tag v-if="scope.row.type === 3">月卡</el-tag> |
|||
<el-tag v-if="scope.row.type === 4">会员IC卡</el-tag> |
|||
<el-tag v-if="scope.row.type === 5">充值卡</el-tag> |
|||
</el-table-column> |
|||
<el-table-column prop="remainingMoney" label="余额"/> |
|||
<el-table-column prop="price" label="购买价格"/> |
|||
<el-table-column label="可用场馆" v-slot="scope"> |
|||
<span>{{ scope.row.siteList.map(item => item.name).join() }}</span> |
|||
</el-table-column> |
|||
<el-table-column prop="num" label="剩余次数"/> |
|||
<el-table-column prop="count" label="总次数"/> |
|||
<el-table-column prop="discount" label="折扣"/> |
|||
<el-table-column prop="month" label="月限"/> |
|||
<el-table-column prop="term" label="年限"/> |
|||
<el-table-column label="付款方式" v-slot="scope"> |
|||
<el-tag type="success" v-if="scope.row.payType === 1">微信支付</el-tag> |
|||
<el-tag type="success" v-if="scope.row.payType === 2">支付宝支付</el-tag> |
|||
<el-tag type="success" v-if="scope.row.payType === 3">现金</el-tag> |
|||
<el-tag type="success" v-if="scope.row.payType === 4">POS机刷卡</el-tag> |
|||
<el-tag type="success" v-if="scope.row.payType === 5">平安健康卡</el-tag> |
|||
</el-table-column> |
|||
<el-table-column label="支付状态" v-slot="scope"> |
|||
<span class="text-green-500" v-if="scope.row.status === 1">已支付</span> |
|||
<span class="text-red-500" v-if="scope.row.status === 2">未支付</span> |
|||
</el-table-column> |
|||
<el-table-column label="时间" v-slot="scope"> |
|||
<div>开卡时间:{{ dayjs(scope.row.createTime * 1000).format('YYYY-MM-DD HH:mm:ss') }}</div> |
|||
<div class="text-blue-500"> |
|||
过期时间:{{ dayjs(scope.row.expireTime * 1000).format('YYYY-MM-DD HH:mm:ss') }} |
|||
</div> |
|||
</el-table-column> |
|||
<el-table-column prop="remark" label="备注"/> |
|||
</el-table> |
|||
|
|||
<page :per-page="perPage" :current-page="currentPage" :total="total" @change-size="changeSize" |
|||
@change-page="changePage"/> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
</template> |
|||
|
|||
<script setup> |
|||
import {onMounted, ref} from 'vue' |
|||
import dayjs from "dayjs"; |
|||
import {pageCard} from "@/api/icCard.js"; |
|||
|
|||
const list = ref([]) |
|||
const loading = ref(true) |
|||
const perPage = ref(20) |
|||
const total = ref(0) |
|||
const currentPage = ref(1) |
|||
|
|||
const changeSize = ({size}) => { |
|||
perPage.value = size |
|||
getList(true) |
|||
} |
|||
|
|||
const changePage = ({page}) => { |
|||
currentPage.value = page |
|||
getList() |
|||
} |
|||
|
|||
const keywords = ref('') |
|||
const createTimeRange = ref([]) |
|||
const getList = async (reload = false) => { |
|||
let createTimeStart = null, createTimeEnd = null, orderTimeStart = null, orderTimeEnd = null |
|||
if (reload) { |
|||
currentPage.value = 1 |
|||
loading.value = true |
|||
} |
|||
loading.value = true |
|||
if (createTimeRange.value && createTimeRange.value.length) { |
|||
createTimeStart = dayjs(createTimeRange.value[0]).unix() |
|||
createTimeEnd = dayjs(createTimeRange.value[1] + ' 23:59:59').unix() |
|||
} |
|||
const res = await pageCard({ |
|||
page: currentPage.value, |
|||
limit: perPage.value, |
|||
keywords: keywords.value ?? null, |
|||
createTimeStart: createTimeStart ?? null, |
|||
createTimeEnd: createTimeEnd ?? null, |
|||
notZeroNumber: true, |
|||
}) |
|||
loading.value = false |
|||
total.value = res.data.count |
|||
list.value = res.data.list |
|||
} |
|||
|
|||
const tableHeight = ref(1080) |
|||
onMounted(async () => { |
|||
tableHeight.value = document.body.clientHeight - 260 |
|||
await getList() |
|||
}) |
|||
</script> |
@ -0,0 +1,126 @@ |
|||
<template> |
|||
<div class="w-full"> |
|||
<div class=" m-6 rounded-xl"> |
|||
<div class="p-3 w-full bg-white rounded-xl"> |
|||
<el-space alignment="flex-end"> |
|||
<div class="flex flex-col justify-start items-start"> |
|||
<span class="text-sm text-gray-500">关键词</span> |
|||
<el-input size="large" style="width: 300px" v-model="keywords" placeholder="姓名/手机号/身份证/IC卡号筛选" |
|||
@keyup.enter.native="getList(true)" |
|||
clearable/> |
|||
</div> |
|||
<div class="flex flex-col justify-start items-start"> |
|||
<span class="text-sm text-gray-500">开卡时间</span> |
|||
<el-date-picker size="large" v-model="createTimeRange" type="daterange" placeholder="开卡时间筛选"></el-date-picker> |
|||
</div> |
|||
<el-button size="large" icon="Search" @click.native="getList(true)" type="primary"> |
|||
搜索 |
|||
</el-button> |
|||
<el-button size="large" icon="RefreshRight" @click.native="init" type="warning" |
|||
margin-left="mx-4">重置 |
|||
</el-button> |
|||
</el-space> |
|||
</div> |
|||
<div class="p-3 w-full rounded-xl mt-4 bg-white"> |
|||
<el-table :data="list" stripe v-loading="loading" :height="tableHeight" size="large"> |
|||
<el-table-column prop="id" label="IC卡号"/> |
|||
<el-table-column prop="code" label="IC卡编号"/> |
|||
<el-table-column label="用户" v-slot="scope"> |
|||
<div>{{ scope.row.username }}</div> |
|||
<div>{{ scope.row.phone }}</div> |
|||
</el-table-column> |
|||
<el-table-column prop="name" label="卡名称"/> |
|||
<el-table-column prop="name" label="卡类型" v-slot="scope"> |
|||
<el-tag v-if="scope.row.type === 1">年卡</el-tag> |
|||
<el-tag v-if="scope.row.type === 2">次卡</el-tag> |
|||
<el-tag v-if="scope.row.type === 3">月卡</el-tag> |
|||
<el-tag v-if="scope.row.type === 4">会员IC卡</el-tag> |
|||
<el-tag v-if="scope.row.type === 5">充值卡</el-tag> |
|||
</el-table-column> |
|||
<el-table-column prop="remainingMoney" label="余额"/> |
|||
<el-table-column prop="price" label="购买价格"/> |
|||
<el-table-column prop="siteNames" label="可用场馆"/> |
|||
<el-table-column prop="num" label="剩余次数"/> |
|||
<el-table-column prop="count" label="总次数"/> |
|||
<el-table-column prop="discount" label="折扣"/> |
|||
<el-table-column prop="month" label="月限"/> |
|||
<el-table-column prop="term" label="年限"/> |
|||
<el-table-column label="支付状态" v-slot="scope"> |
|||
<span class="text-green-500" v-if="scope.row.status === 1">已支付</span> |
|||
<span class="text-red-500" v-if="scope.row.status === 2">未支付</span> |
|||
<span class="text-red-500" v-if="scope.row.status === 3">已退款</span> |
|||
</el-table-column> |
|||
<el-table-column label="是否已开具发票" v-slot="scope"> |
|||
<span class="text-green-500" v-if="scope.row.isInvoice === 1">已开</span> |
|||
<span class="text-red-500" v-if="scope.row.isInvoice === 2">未开</span> |
|||
<span class="text-gray-500" v-if="scope.row.isInvoice === 3">不可未开</span> |
|||
</el-table-column> |
|||
<el-table-column label="时间" v-slot="scope"> |
|||
<div>开卡时间:{{ dayjs(scope.row.createTime * 1000).format('YYYY-MM-DD HH:mm:ss') }}</div> |
|||
<div class="text-blue-500"> |
|||
过期时间:{{ dayjs(scope.row.expireTime * 1000).format('YYYY-MM-DD HH:mm:ss') }} |
|||
</div> |
|||
</el-table-column> |
|||
<el-table-column prop="remark" label="备注"/> |
|||
</el-table> |
|||
|
|||
<page :per-page="perPage" :current-page="currentPage" :total="total" @change-size="changeSize" |
|||
@change-page="changePage"/> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
</template> |
|||
|
|||
<script setup> |
|||
import {onMounted, ref} from 'vue' |
|||
import dayjs from "dayjs"; |
|||
import {pageUsersVip} from "@/api/usersVip.js"; |
|||
|
|||
const list = ref([]) |
|||
const loading = ref(true) |
|||
const perPage = ref(20) |
|||
const total = ref(0) |
|||
const currentPage = ref(1) |
|||
|
|||
const changeSize = ({size}) => { |
|||
perPage.value = size |
|||
getList(true) |
|||
} |
|||
|
|||
const changePage = ({page}) => { |
|||
currentPage.value = page |
|||
getList() |
|||
} |
|||
|
|||
const keywords = ref('') |
|||
const createTimeRange = ref([]) |
|||
const getList = async (reload = false) => { |
|||
let createTimeStart = null, createTimeEnd = null |
|||
if (reload) { |
|||
currentPage.value = 1 |
|||
loading.value = true |
|||
} |
|||
loading.value = true |
|||
if (createTimeRange.value && createTimeRange.value.length) { |
|||
createTimeStart = dayjs(createTimeRange.value[0]).unix() |
|||
createTimeEnd = dayjs(createTimeRange.value[1] + ' 23:59:59').unix() |
|||
} |
|||
const res = await pageUsersVip({ |
|||
page: currentPage.value, |
|||
limit: perPage.value, |
|||
keywords: keywords.value ?? null, |
|||
createTimeStart: createTimeStart ?? null, |
|||
createTimeEnd: createTimeEnd ?? null, |
|||
forAdmin: true, |
|||
}) |
|||
loading.value = false |
|||
total.value = res.data.count |
|||
list.value = res.data.list |
|||
} |
|||
|
|||
const tableHeight = ref(1080) |
|||
onMounted(async () => { |
|||
tableHeight.value = document.body.clientHeight - 260 |
|||
await getList() |
|||
}) |
|||
</script> |
@ -0,0 +1,163 @@ |
|||
<template> |
|||
<div class="w-full"> |
|||
<div class=" m-6 rounded-xl"> |
|||
<div class="p-3 w-full bg-white rounded-xl"> |
|||
<el-space alignment="flex-end"> |
|||
<div class="flex flex-col justify-start items-start"> |
|||
<span class="text-sm text-gray-500">关键词</span> |
|||
<el-input style="width: 300px" v-model="keywords" placeholder="姓名/手机号/订单号/IC卡号筛选" |
|||
@keyup.enter.native="getList(true)" |
|||
clearable/> |
|||
</div> |
|||
<div class="flex flex-col justify-start items-start"> |
|||
<span class="text-sm text-gray-500">下单时间</span> |
|||
<el-date-picker v-model="createTimeRange" type="daterange" placeholder="下单时间筛选"></el-date-picker> |
|||
</div> |
|||
<div class="flex flex-col justify-start items-start"> |
|||
<span class="text-sm text-gray-500">使用场地时间</span> |
|||
<el-date-picker v-model="orderTimeRange" type="daterange" placeholder="使用场地时间筛选"></el-date-picker> |
|||
</div> |
|||
<el-button icon="Search" @click.native="getList(true)" type="primary"> |
|||
搜索 |
|||
</el-button> |
|||
<el-button icon="RefreshRight" @click.native="init" type="warning" |
|||
margin-left="mx-4">重置 |
|||
</el-button> |
|||
</el-space> |
|||
</div> |
|||
<div class="p-3 w-full rounded-xl mt-4 bg-white"> |
|||
<el-table :data="list" stripe v-loading="loading" :height="tableHeight" @row-dblclick="openInfo"> |
|||
<el-table-column prop="orderNum" label="订单号"/> |
|||
<el-table-column prop="title" label="场地名称" v-slot="scope"> |
|||
<div>{{ scope.row.siteName }}</div> |
|||
<div>{{ scope.row.dateTime }} ¥{{ scope.row.totalPrice }}元</div> |
|||
</el-table-column> |
|||
<el-table-column label="VIP卡" v-slot="scope"> |
|||
<p>{{ scope.row.thinkVip.name }}</p> |
|||
<p>{{ scope.row.thinkVip.code }}</p> |
|||
</el-table-column> |
|||
<el-table-column label="用户" v-slot="scope"> |
|||
<div>{{ scope.row.name }}</div> |
|||
<div>{{ scope.row.phone }}</div> |
|||
</el-table-column> |
|||
<el-table-column label="订单金额" v-slot="scope"> |
|||
<div>¥{{ scope.row.totalPrice }}</div> |
|||
</el-table-column> |
|||
<el-table-column label="实付金额" v-slot="scope"> |
|||
<div>¥{{ scope.row.payPrice }}</div> |
|||
</el-table-column> |
|||
<el-table-column label="支付状态" v-slot="scope"> |
|||
<span class="text-green-500" v-if="scope.row.payStatus === 1">已支付</span> |
|||
<span class="text-red-500" v-if="scope.row.payStatus === 2">未支付</span> |
|||
<span v-if="scope.row.payStatus === 0 || scope.row.payStatus === 3">未付款,占场中</span> |
|||
</el-table-column> |
|||
<el-table-column label="订单状态" v-slot="scope"> |
|||
<span v-if="scope.row.orderStatus === 1" class="text-green-500" |
|||
>已完成</span> |
|||
<span v-if="scope.row.orderStatus === 2" class="ele-text-placeholder" |
|||
>未使用</span> |
|||
<span v-if="scope.row.orderStatus === 3" class="text-gray-400" |
|||
>已取消</span> |
|||
<span v-if="scope.row.orderStatus === 4" class="ele-text-warning" |
|||
>退款申请中</span> |
|||
<span v-if="scope.row.orderStatus === 5">退款被拒绝</span> |
|||
<span v-if="scope.row.orderStatus === 6">退款成功</span> |
|||
<span v-if="scope.row.orderStatus === 7">客户端申请退款</span> |
|||
<span v-if="scope.row.orderStatus === 9">未完成</span> |
|||
</el-table-column> |
|||
<el-table-column label="时间" v-slot="scope"> |
|||
<div>下单时间:{{ dayjs(scope.row.createTime * 1000).format('YYYY-MM-DD HH:mm:ss') }}</div> |
|||
<div class="text-green-500">更新时间:{{ |
|||
dayjs(scope.row.updateTime * 1000).format('YYYY-MM-DD HH:mm:ss') |
|||
}} |
|||
</div> |
|||
<div class="text-blue-500" v-if="scope.row.payTime"> |
|||
支付时间:{{ dayjs(scope.row.payTime * 1000).format('YYYY-MM-DD HH:mm:ss') }} |
|||
</div> |
|||
</el-table-column> |
|||
<el-table-column label="操作"> |
|||
<template v-slot="scope"> |
|||
<el-button type="text" @click="openInfo(scope.row)">详情</el-button> |
|||
</template> |
|||
</el-table-column> |
|||
</el-table> |
|||
|
|||
<page :per-page="perPage" :current-page="currentPage" :total="total" @change-size="changeSize" |
|||
@change-page="changePage"/> |
|||
</div> |
|||
</div> |
|||
<OrderInfo v-model="showInfo" v-if="showInfo" :order-id="orderId"></OrderInfo> |
|||
</div> |
|||
</template> |
|||
|
|||
<script setup> |
|||
import {onMounted, ref} from 'vue' |
|||
import {pageOrder} from "@/api/order.js"; |
|||
import dayjs from "dayjs"; |
|||
import OrderInfo from "@/components/OrderInfo.vue"; |
|||
|
|||
const list = ref([]) |
|||
const loading = ref(true) |
|||
const perPage = ref(20) |
|||
const total = ref(0) |
|||
const currentPage = ref(1) |
|||
|
|||
const changeSize = ({size}) => { |
|||
perPage.value = size |
|||
getList(true) |
|||
} |
|||
|
|||
const changePage = ({page}) => { |
|||
currentPage.value = page |
|||
getList() |
|||
} |
|||
|
|||
const keywords = ref('') |
|||
const payType = ref(null) |
|||
const createTimeRange = ref([]) |
|||
const orderTimeRange = ref([]) |
|||
const getList = async (reload = false) => { |
|||
let createTimeStart = null, createTimeEnd = null, orderTimeStart = null, orderTimeEnd = null |
|||
if (reload) { |
|||
currentPage.value = 1 |
|||
loading.value = true |
|||
} |
|||
loading.value = true |
|||
if (createTimeRange.value && createTimeRange.value.length) { |
|||
createTimeStart = dayjs(createTimeRange.value[0]).unix() |
|||
createTimeEnd = dayjs(createTimeRange.value[1] + ' 23:59:59').unix() |
|||
} |
|||
if (orderTimeRange.value && orderTimeRange.value.length) { |
|||
orderTimeStart = dayjs(orderTimeRange.value[0]).unix() |
|||
orderTimeEnd = dayjs(orderTimeRange.value[1] + ' 23:59:59').unix() |
|||
} |
|||
const res = await pageOrder({ |
|||
page: currentPage.value, |
|||
limit: perPage.value, |
|||
keywords: keywords.value ?? null, |
|||
createTimeStart: createTimeStart ?? null, |
|||
createTimeEnd: createTimeEnd ?? null, |
|||
orderTimeStart: orderTimeStart ?? null, |
|||
orderTimeEnd: orderTimeEnd ?? null, |
|||
forAdmin: true, |
|||
useVip: true, |
|||
}) |
|||
loading.value = false |
|||
total.value = res.data.count |
|||
list.value = res.data.list |
|||
} |
|||
|
|||
const showInfo = ref(false) |
|||
const orderId = ref() |
|||
const openInfo = (row) => { |
|||
console.log(row) |
|||
orderId.value = row.id |
|||
showInfo.value = true |
|||
} |
|||
|
|||
const tableHeight = ref(1080) |
|||
onMounted(async () => { |
|||
tableHeight.value = document.body.clientHeight - 260 |
|||
await getList() |
|||
}) |
|||
</script> |
@ -0,0 +1,59 @@ |
|||
<template> |
|||
<div class="flex justify-center items-center flex-col" style="height: calc(100vh - 80px)"> |
|||
<div class="flex justify-center items-center w-1/3"> |
|||
<div class="flex justify-center items-center rounded-xl item-bg m-4 w-1/3" @click="showNewCard = true"> |
|||
开卡 |
|||
</div> |
|||
<div class="flex justify-center items-center rounded-xl item-bg m-4 w-1/3" @click="showReNewCard = true"> |
|||
续卡 |
|||
</div> |
|||
<div class="flex justify-center items-center rounded-xl item-bg m-4 w-1/3" @click="showSiteList = true"> |
|||
预定场地 |
|||
</div> |
|||
</div> |
|||
<div class="flex justify-center items-center w-1/3"> |
|||
<div class="flex justify-center items-center rounded-xl item-bg m-4 w-1/2" @click="showDeposit = true"> |
|||
收取押金 |
|||
</div> |
|||
<div class="flex justify-center items-center rounded-xl item-bg m-4 w-1/2" @click="deving"> |
|||
我的报表 |
|||
</div> |
|||
<!-- <div class="flex justify-center items-center rounded-xl item-bg m-4 w-1/3">--> |
|||
<!-- 转卡服务--> |
|||
<!-- </div>--> |
|||
</div> |
|||
</div> |
|||
<NewCard v-model="showNewCard" v-if="showNewCard"></NewCard> |
|||
<ReNewCard v-model="showReNewCard" v-if="showReNewCard"></ReNewCard> |
|||
<SelectSite v-model="showSiteList" v-if="showSiteList"></SelectSite> |
|||
<Deposite v-model="showDeposit" v-if="showDeposit"></Deposite> |
|||
</template> |
|||
|
|||
<script setup> |
|||
import {onMounted, reactive, ref} from 'vue' |
|||
import NewCard from "@/components/NewCard.vue"; |
|||
import ReNewCard from "@/components/ReNewCard.vue"; |
|||
import SelectSite from "@/components/SelectSite.vue"; |
|||
import Deposite from "@/components/Deposite.vue"; |
|||
import {ElMessage} from "element-plus"; |
|||
|
|||
const showNewCard = ref(false) |
|||
const showReNewCard = ref(false) |
|||
const showSiteList = ref(false) |
|||
const showDeposit = ref(false) |
|||
|
|||
const deving = () => { |
|||
ElMessage.info('开发中,暂未开放') |
|||
} |
|||
</script> |
|||
|
|||
<style scope> |
|||
.item-bg { |
|||
background: linear-gradient(to bottom, #27ABAB, #27AB49); |
|||
height: 10rem; |
|||
flex-shrink: 0; |
|||
color: white; |
|||
cursor: pointer; |
|||
font-size: 1.25rem; |
|||
} |
|||
</style> |
@ -0,0 +1,17 @@ |
|||
import * as VueRouter from "vue-router"; |
|||
import Home from '@/views/Home.vue' |
|||
|
|||
const routes = [ |
|||
{ |
|||
path: '/:page', |
|||
name: 'home', |
|||
component: Home |
|||
} |
|||
] |
|||
|
|||
const router = VueRouter.createRouter({ |
|||
history: VueRouter.createWebHashHistory(), |
|||
routes, |
|||
}) |
|||
|
|||
export default router |
@ -0,0 +1,10 @@ |
|||
import {defineStore} from 'pinia' |
|||
import {computed, ref} from "vue"; |
|||
|
|||
|
|||
export const reloadFlagStore = defineStore('reloadFlag', () => { |
|||
const data = ref(null) |
|||
const getData = computed(() => data.value) |
|||
const setData = (value) => data.value = value |
|||
return {getData, setData, data} |
|||
}) |
@ -0,0 +1,10 @@ |
|||
@tailwind base; |
|||
@tailwind components; |
|||
@tailwind utilities; |
|||
|
|||
|
|||
@layer components { |
|||
.card { |
|||
@apply shadow-md rounded-lg p-4 bg-white; |
|||
} |
|||
} |
@ -0,0 +1,205 @@ |
|||
<template> |
|||
<el-container class="w-screen h-screen relative"> |
|||
<div class="w-screen h-screen absolute left-0 top-0 bg"/> |
|||
<el-header class="z-10"> |
|||
<div class="flex justify-between items-center bg-white w-full px-4 rounded-full mt-2"> |
|||
<el-space> |
|||
<div class="flex flex-col justify-start items-start z-10 text-sm"> |
|||
<span>欢迎您, {{ username }}</span> |
|||
<span class="mt-2">{{ time }}</span> |
|||
</div> |
|||
<div class="ml-4 flex justify-start items-center" v-if="activeIndex !== 'Index'"> |
|||
<div |
|||
class="cursor-pointer flex flex-col justify-center items-center p-1 rounded my-0.5 mx-2 bg-emerald-400 text-white" |
|||
style="width: 100px" @click="showNewCard = true"> |
|||
<el-icon size="32"> |
|||
<CreditCard></CreditCard> |
|||
</el-icon> |
|||
<span class="text-sm">开卡</span> |
|||
</div> |
|||
<div |
|||
class="cursor-pointer flex flex-col justify-center items-center p-1 rounded my-0.5 mx-2 bg-emerald-400 text-white" |
|||
style="width: 100px" @click="showReNewCard = true"> |
|||
<el-icon size="32"> |
|||
<Money></Money> |
|||
</el-icon> |
|||
<span class="text-sm">续卡</span> |
|||
</div> |
|||
<div |
|||
class="cursor-pointer flex flex-col justify-center items-center p-1 rounded my-0.5 mx-2 bg-emerald-400 text-white" |
|||
style="width: 100px" @click="showSiteList = true"> |
|||
<el-icon size="32"> |
|||
<Football></Football> |
|||
</el-icon> |
|||
<span class="text-sm">预定场地</span> |
|||
</div> |
|||
<div |
|||
class="cursor-pointer flex flex-col justify-center items-center p-1 rounded my-0.5 mx-2 bg-emerald-400 text-white" |
|||
style="width: 100px" @click="showDeposit = true"> |
|||
<el-icon size="32"> |
|||
<Sell></Sell> |
|||
</el-icon> |
|||
<span class="text-sm">收取押金</span> |
|||
</div> |
|||
<!-- <el-button round plain type="primary" @click="showNewCard = true">开卡</el-button>--> |
|||
<!-- <el-button round plain type="primary" @click="showReNewCard = true">续卡</el-button>--> |
|||
<!-- <el-button round plain type="primary" @click="showSiteList = true">预定场地</el-button>--> |
|||
<!-- <el-button round plain type="success" @click="showDeposit = true">收取押金</el-button>--> |
|||
<!-- <el-button round plain type="success">我的报表</el-button>--> |
|||
<!-- <el-button round plain type="success">转卡服务</el-button>--> |
|||
</div> |
|||
</el-space> |
|||
<div class="rounded-full pr-10"> |
|||
<el-menu |
|||
:default-active="activeIndex" |
|||
class="el-menu-demo" |
|||
mode="horizontal" |
|||
:ellipsis="false" |
|||
@select="selectMenu" |
|||
active-text-color="#27AB49" |
|||
> |
|||
<el-menu-item index="Index">主页</el-menu-item> |
|||
<el-menu-item index="IcCard">卡号列表</el-menu-item> |
|||
<el-menu-item index="ReNewIcCard">续卡列表</el-menu-item> |
|||
<el-menu-item index="Order">订单列表</el-menu-item> |
|||
<el-menu-item index="UsersVip">VIP购卡记录列表</el-menu-item> |
|||
<!-- <el-sub-menu index="4">--> |
|||
<!-- <template #title>电子卡列表</template>--> |
|||
<!-- <el-menu-item index="UsersVip">VIP购卡记录列表</el-menu-item>--> |
|||
<!-- <el-menu-item index="VipCardLog">VIP卡消费流水</el-menu-item>--> |
|||
<!-- </el-sub-menu>--> |
|||
<el-menu-item index="Deposit">押金列表</el-menu-item> |
|||
<el-menu-item index="ChangePwd">修改密码</el-menu-item> |
|||
<el-menu-item index="Logout"> |
|||
<el-button type="danger" size="large" round>退出登录</el-button> |
|||
</el-menu-item> |
|||
<el-menu-item> |
|||
<span class="text-sm">当前版本:{{ version }}</span> |
|||
</el-menu-item> |
|||
</el-menu> |
|||
</div> |
|||
</div> |
|||
</el-header> |
|||
<el-main class="flex flex-col z-20" style="padding: 0"> |
|||
<keep-alive> |
|||
<component ref="ComponentRef" :is="activeIndex" :keep-alive="true" class="w-full"/> |
|||
</keep-alive> |
|||
</el-main> |
|||
</el-container> |
|||
<NewCard v-model="showNewCard" v-if="showNewCard"></NewCard> |
|||
<ReNewCard v-model="showReNewCard" v-if="showReNewCard"></ReNewCard> |
|||
<SelectSite v-model="showSiteList" v-if="showSiteList"></SelectSite> |
|||
<ChangePwd v-model="showChangePwd" v-if="showChangePwd"></ChangePwd> |
|||
<Deposite v-model="showDeposit" v-if="showDeposit"></Deposite> |
|||
</template> |
|||
|
|||
<script> |
|||
import Index from '@/pages/index/Index.vue' |
|||
import Order from '@/pages/Order.vue' |
|||
import IcCard from '@/pages/IcCard.vue' |
|||
import ReNewIcCard from '@/pages/ReNewIcCard.vue' |
|||
import Deposit from '@/pages/Deposit.vue' |
|||
import UsersVip from '@/pages/UsersVip.vue' |
|||
import VipCardLog from '@/pages/VipCardLog.vue' |
|||
|
|||
export default { |
|||
components: { |
|||
Index, |
|||
Order, |
|||
IcCard, |
|||
ReNewIcCard, |
|||
Deposit, |
|||
UsersVip, |
|||
VipCardLog, |
|||
} |
|||
} |
|||
</script> |
|||
|
|||
<script setup> |
|||
import {ref, watch, onMounted, nextTick, reactive} from 'vue' |
|||
import {clearUserInfo, getUserInfo} from '@/api/common.js' |
|||
import {useRoute, useRouter} from 'vue-router' |
|||
import {ElMessageBox} from "element-plus"; |
|||
import dayjs from "dayjs"; |
|||
import NewCard from "@/components/NewCard.vue"; |
|||
import ReNewCard from "@/components/ReNewCard.vue"; |
|||
import SelectSite from "@/components/SelectSite.vue"; |
|||
import ChangePwd from "@/components/ChangePwd.vue"; |
|||
import Deposite from "@/components/Deposite.vue"; |
|||
|
|||
const version = ref('250119') |
|||
|
|||
const route = useRoute() |
|||
const router = useRouter() |
|||
|
|||
const currentView = ref(null) |
|||
const activeIndex = ref('Index') |
|||
const username = getUserInfo().username |
|||
|
|||
const time = ref() |
|||
const setCurrentTime = () => { |
|||
time.value = dayjs().format('YYYY-MM-DD HH:mm:ss') |
|||
setTimeout(() => { |
|||
setCurrentTime() |
|||
}, 1000) |
|||
} |
|||
setCurrentTime() |
|||
|
|||
watch(route, (path) => { |
|||
currentView.value = path.path |
|||
activeIndex.value = currentView.value.split('/')[1] |
|||
console.log(activeIndex.value) |
|||
// getDotData() |
|||
}) |
|||
|
|||
const showChangePwd = ref(false) |
|||
|
|||
const selectMenu = menu => { |
|||
switch (menu) { |
|||
case 'Logout' : { |
|||
ElMessageBox.confirm('您确定要退出登录吗?', '提示', { |
|||
confirmButtonText: '确定', |
|||
cancelButtonText: '取消', |
|||
type: 'warning' |
|||
}).then(() => { |
|||
clearUserInfo() |
|||
router.push(`/Login`) |
|||
}).catch(() => { |
|||
// console.log('取消'); |
|||
}); |
|||
} |
|||
break; |
|||
case 'ChangePwd' : { |
|||
showChangePwd.value = true |
|||
} |
|||
break; |
|||
default : { |
|||
router.push(`/${menu}`) |
|||
} |
|||
} |
|||
} |
|||
|
|||
const showNewCard = ref(false) |
|||
const showReNewCard = ref(false) |
|||
const showSiteList = ref(false) |
|||
const showDeposit = ref(false) |
|||
|
|||
onMounted(async () => { |
|||
if (!getUserInfo().token) { |
|||
await clearUserInfo() |
|||
await router.push(`/Login`) |
|||
} |
|||
const urlArr = window.location.href.split('/') |
|||
activeIndex.value = urlArr[urlArr.length - 1] |
|||
if (!activeIndex.value) await router.push(`/Index`) |
|||
}) |
|||
</script> |
|||
|
|||
|
|||
<style scoped> |
|||
.bg { |
|||
z-index: 0; |
|||
background: linear-gradient(to bottom, #27ABAB44, #27AB4944), url("@/assets/bg.jpg") no-repeat 100% 100%; |
|||
opacity: .9; |
|||
} |
|||
</style> |
@ -0,0 +1,57 @@ |
|||
<template> |
|||
<div class="flex w-screen h-screen justify-center items-center bg "> |
|||
<div class="w-1/4 flex justify-center items-center rounded-xl bg-white"> |
|||
<!-- <img src="@/assets/images/login-icon.png" alt="" class="mr-1 w-2/4">--> |
|||
<div class="flex justify-center items-center flex-col w-full p-4 shadow-xl rounded-xl"> |
|||
<!-- <img src="@/assets/images/logo.jpg" alt="" style="height: 5rem">--> |
|||
<span class="text-center my-3 text-2xl font-bold">营业端管理登录</span> |
|||
<el-form class="w-full flex flex-col items-end" label-width="80"> |
|||
<el-form-item label="用户名" class="w-full"> |
|||
<el-input v-model="username" placeholder="请输入用户名"/> |
|||
</el-form-item> |
|||
<el-form-item label="密码" class="w-full"> |
|||
<el-input v-model="password" type="password" @keyup.enter.native="login" |
|||
placeholder="请输入密码"/> |
|||
</el-form-item> |
|||
<el-button @click.native="login" type="primary" class="w-11/12" color="#27AB49">登录</el-button> |
|||
</el-form> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
</template> |
|||
|
|||
<script setup> |
|||
import {ref} from 'vue' |
|||
import {useRouter} from 'vue-router' |
|||
import {loginReq} from '@/api/admin.js' |
|||
import {setUserInfo} from '@/api/common.js' |
|||
import {ElMessage} from 'element-plus' |
|||
|
|||
const router = useRouter() |
|||
|
|||
let username = ref(null) |
|||
let password = ref(null) |
|||
|
|||
const login = async () => { |
|||
const res = await loginReq({username: username.value, password: password.value}) |
|||
if (res.data) { |
|||
ElMessage.success({ |
|||
message: '登陆成功' |
|||
}); |
|||
setUserInfo(res.data) |
|||
await router.push('/Index') |
|||
} |
|||
} |
|||
|
|||
|
|||
</script> |
|||
|
|||
<style scope> |
|||
.bg { |
|||
background-image: url("@/assets/bg.jpg"); |
|||
background-size: cover; |
|||
background-repeat: no-repeat; |
|||
width: 100vw; |
|||
height: 100vh; |
|||
} |
|||
</style> |
@ -0,0 +1,8 @@ |
|||
/** @type {import('tailwindcss').Config} */ |
|||
module.exports = { |
|||
content: ["./src/**/*.vue"], |
|||
theme: { |
|||
extend: {}, |
|||
}, |
|||
plugins: [], |
|||
} |
@ -0,0 +1,15 @@ |
|||
import {defineConfig} from 'vite' |
|||
import vue from '@vitejs/plugin-vue' |
|||
// gzip
|
|||
import viteCompression from 'vite-plugin-compression' |
|||
|
|||
import {resolve} from "path"; |
|||
|
|||
export default defineConfig({ |
|||
plugins: [vue(), viteCompression()], |
|||
resolve: { |
|||
alias: { |
|||
'@': resolve(__dirname, "src") |
|||
} |
|||
}, |
|||
}) |
@ -0,0 +1,19 @@ |
|||
import viteBaseConfig from './vite.base.config.js' |
|||
import viteDevConfig from './src/config/vite.dev.js' |
|||
import viteBuildConfig from './src/config/vite.build.js' |
|||
import {defineConfig} from "vite"; |
|||
|
|||
|
|||
export default defineConfig(({mode}) => { |
|||
if (mode === "dev") { |
|||
return { |
|||
...viteBaseConfig, |
|||
...viteDevConfig, |
|||
}; |
|||
} else { |
|||
return { |
|||
...viteBaseConfig, |
|||
...viteBuildConfig, |
|||
}; |
|||
} |
|||
}); |
Loading…
Reference in new issue