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