Compare commits
7 Commits
42eae0b1cd
...
1582ca6f2f
Author | SHA1 | Date |
---|---|---|
|
1582ca6f2f | |
|
4891d9376c | |
|
7a9847bb25 | |
|
533a94ca9b | |
|
adf5bc4d20 | |
|
ac5d9292ca | |
|
9c81c228ee |
|
@ -0,0 +1,55 @@
|
|||
import { request } from '@/http/axios'
|
||||
import {
|
||||
GetTokenParams,
|
||||
LoginData,
|
||||
LogoutResponse,
|
||||
SmsSendResponse,
|
||||
TokenResponse,
|
||||
VerifySmsParams,
|
||||
WechatQrCodeParams
|
||||
} from './type'
|
||||
|
||||
/** 获取临时令牌 */
|
||||
export function getTokenApi(appName: string) {
|
||||
return request<ApiResponseData<TokenResponse>>({
|
||||
url: '/wx/login/getToken',
|
||||
method: 'get',
|
||||
params: { appName }
|
||||
})
|
||||
}
|
||||
|
||||
/** 获取微信登录二维码 */
|
||||
export function getWechatQrCodeApi(token: string) {
|
||||
return request<ApiResponseData<string>>({
|
||||
url: '/wx/login/wechat/qrcode',
|
||||
method: 'get',
|
||||
params: { token }
|
||||
})
|
||||
}
|
||||
|
||||
/** 发送短信验证码 */
|
||||
export function sendSmsApi(token: string, tel: string) {
|
||||
return request<ApiResponseData<SmsSendResponse>>({
|
||||
url: '/wx/login/sendSms',
|
||||
method: 'post',
|
||||
params: { token, tel }
|
||||
})
|
||||
}
|
||||
|
||||
/** 验证短信验证码 */
|
||||
export function verifySmsApi(params: VerifySmsParams) {
|
||||
return request<ApiResponseData<LoginData>>({
|
||||
url: '/wx/login/verifySms',
|
||||
method: 'post',
|
||||
params
|
||||
})
|
||||
}
|
||||
|
||||
/** 用户退出登录 */
|
||||
export function logoutApi(token: string) {
|
||||
return request<ApiResponseData<LogoutResponse>>({
|
||||
url: '/wx/login/logout',
|
||||
method: 'post',
|
||||
params: { token }
|
||||
})
|
||||
}
|
|
@ -0,0 +1,59 @@
|
|||
/** 令牌响应 */
|
||||
export interface TokenResponse {
|
||||
/** 认证令牌 */
|
||||
token: string
|
||||
}
|
||||
|
||||
/** 退出登录响应 */
|
||||
export interface LogoutResponse {
|
||||
/** 是否成功 */
|
||||
success: boolean
|
||||
}
|
||||
|
||||
/** 短信发送响应 */
|
||||
export interface SmsSendResponse {
|
||||
/** 发送状态 */
|
||||
success: boolean
|
||||
/** 错误信息 */
|
||||
message?: string
|
||||
}
|
||||
|
||||
/** 登录数据 */
|
||||
export interface LoginData {
|
||||
/** 用户头像 */
|
||||
face_img: string
|
||||
/** 登录状态 */
|
||||
success: boolean
|
||||
/** 用户性别 */
|
||||
sex: string
|
||||
/** 用户姓名 */
|
||||
name: string
|
||||
/** 用户ID */
|
||||
userid: string
|
||||
/** 是否已注册 */
|
||||
registered: boolean
|
||||
/** 联系电话 */
|
||||
tel: string
|
||||
}
|
||||
|
||||
/** 获取令牌参数 */
|
||||
export type GetTokenParams = {
|
||||
/** 应用名称 */
|
||||
appName: string
|
||||
}
|
||||
|
||||
/** 微信二维码参数 */
|
||||
export type WechatQrCodeParams = {
|
||||
/** 认证令牌 */
|
||||
token: string
|
||||
}
|
||||
|
||||
/** 短信验证参数 */
|
||||
export type VerifySmsParams = {
|
||||
/** 认证令牌 */
|
||||
token: string
|
||||
/** 手机号码 */
|
||||
tel: string
|
||||
/** 验证码 */
|
||||
vcode: string
|
||||
}
|
|
@ -1,5 +1,15 @@
|
|||
import { request } from '@/http/axios'
|
||||
import { SubmitApprovalRequestData, SubmitApprovalResponseData } from './type'
|
||||
import { SubmitApprovalRequestData, SubmitApprovalResponseData, SearchApiReturnApprovalQuery, ApiResponsePageData, ReturnApprovalEntity, HandleApprovalRequestData } from './type'
|
||||
|
||||
export const getApprovalListApi = (params: SearchApiReturnApprovalQuery) => {
|
||||
return request<ApiResponsePageData<ReturnApprovalEntity>>({
|
||||
url: 'approval/list',
|
||||
method: 'get',
|
||||
params
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
|
||||
export const submitApprovalApi = (data: SubmitApprovalRequestData) => {
|
||||
return request<SubmitApprovalResponseData>({
|
||||
|
@ -8,3 +18,11 @@ export const submitApprovalApi = (data: SubmitApprovalRequestData) => {
|
|||
data
|
||||
})
|
||||
}
|
||||
|
||||
export const handleApprovalApi = (data: HandleApprovalRequestData) => {
|
||||
return request<ApiResponseMsgData<string>>({
|
||||
url: 'approval/handle',
|
||||
method: 'post',
|
||||
data
|
||||
})
|
||||
}
|
||||
|
|
|
@ -2,6 +2,65 @@ export interface SubmitApprovalRequestData {
|
|||
orderGoodsId: number
|
||||
returnQuantity: number
|
||||
returnImages: string
|
||||
returnRemark: string
|
||||
}
|
||||
|
||||
export interface HandleApprovalRequestData {
|
||||
/** 审批ID */
|
||||
approvalId: number
|
||||
/** 审批状态 */
|
||||
status: number
|
||||
returnAmount: number
|
||||
auditImages: string
|
||||
auditRemark: string
|
||||
}
|
||||
|
||||
export interface SearchApiReturnApprovalQuery {
|
||||
pageNum: number
|
||||
pageSize: number
|
||||
approvalId?: number
|
||||
orderId?: number
|
||||
goodsId?: number
|
||||
status?: number
|
||||
startTime?: string
|
||||
endTime?: string
|
||||
}
|
||||
|
||||
export interface ApiResponsePageData<T> {
|
||||
code: number
|
||||
msg: string
|
||||
data: {
|
||||
total: number
|
||||
rows: T[]
|
||||
}
|
||||
}
|
||||
|
||||
export interface ReturnApprovalEntity {
|
||||
approvalId: number
|
||||
orderId: number
|
||||
goodsId: number
|
||||
/** 关联订单商品ID */
|
||||
orderGoodsId: number
|
||||
/** 归还数量 */
|
||||
returnQuantity: number
|
||||
/** 商品单价 */
|
||||
goodsPrice: number
|
||||
status: number
|
||||
returnAmount: number
|
||||
/** 归还图片路径数组 */
|
||||
returnImages: string
|
||||
/** 审核图片路径数组 */
|
||||
auditImages: string
|
||||
/** 归还说明 */
|
||||
returnRemark: string
|
||||
/** 审核说明 */
|
||||
auditRemark: string
|
||||
createTime: string
|
||||
updateTime: string
|
||||
/** 商品名称 */
|
||||
goodsName: string
|
||||
/** 封面图URL */
|
||||
coverImg: string
|
||||
}
|
||||
|
||||
export type SubmitApprovalResponseData = ApiResponseMsgData<{
|
||||
|
|
|
@ -16,10 +16,21 @@ export type category = {
|
|||
}
|
||||
|
||||
export interface SubmitOrderRequestData {
|
||||
/** 微信用户唯一标识 */
|
||||
openid: string;
|
||||
/** 系统用户ID */
|
||||
userid: string;
|
||||
/** 企业ID */
|
||||
corpid: string;
|
||||
/** 支付类型 wechat:微信 balance:余额 */
|
||||
paymentType: 'wechat' | 'balance';
|
||||
/** 联系电话 */
|
||||
mobile: string;
|
||||
/** 企业微信用户ID或汇邦云用户ID */
|
||||
qyUserid: string;
|
||||
/** 是否内部订单 0否 1汇邦云用户 2企业微信用户 */
|
||||
isInternal: number;
|
||||
/** 订单商品明细列表 */
|
||||
goodsList: Array<{
|
||||
goodsId: number
|
||||
quantity: number
|
||||
|
|
|
@ -3,7 +3,7 @@ const router = useRouter()
|
|||
|
||||
const tabbarItemList = computed(() => {
|
||||
const routes = router.getRoutes()
|
||||
return routes.filter(route => route.meta.layout?.tabbar?.showTabbar)
|
||||
return routes.filter(route => route.meta.layout?.tabbar?.showTabbar && route.path !== '/cabinet')
|
||||
.map(route => ({
|
||||
title: route.meta.title,
|
||||
icon: route.meta.layout?.tabbar?.icon,
|
||||
|
|
|
@ -0,0 +1,358 @@
|
|||
<script setup lang="ts">
|
||||
import { ref } from 'vue'
|
||||
import { showConfirmDialog, showSuccessToast, showToast, UploaderFileListItem, Popup, Picker } from 'vant'
|
||||
|
||||
const showStatusPicker = ref(false)
|
||||
const showPreview = ref(false)
|
||||
const currentPreviewImage = ref('')
|
||||
const statusMap: { [key: number]: string } = {
|
||||
1: '待审核',
|
||||
2: '已通过',
|
||||
3: '已驳回'
|
||||
}
|
||||
|
||||
const statusOptions = [
|
||||
{ text: '待审核', value: 1 },
|
||||
{ text: '通过', value: 2 },
|
||||
{ text: '驳回', value: 3 }
|
||||
]
|
||||
import axios from "axios"
|
||||
import { handleApprovalApi } from '@/common/apis/approval'
|
||||
import type { HandleApprovalRequestData } from '@/common/apis/approval/type'
|
||||
import { useRoute, useRouter } from 'vue-router'
|
||||
import { useApprovalStore } from '@/pinia/stores/approval'
|
||||
|
||||
const { VITE_APP_BASE_API } = import.meta.env;
|
||||
const router = useRouter()
|
||||
const route = useRoute()
|
||||
const approvalStore = useApprovalStore()
|
||||
|
||||
const formData = ref<HandleApprovalRequestData>({
|
||||
approvalId: approvalStore.currentApproval?.approvalId || 0,
|
||||
status: 1,
|
||||
returnAmount: 0,
|
||||
auditImages: '',
|
||||
auditRemark: ''
|
||||
})
|
||||
|
||||
const submitting = ref(false)
|
||||
const fileList = ref<UploaderFileListItem[]>([])
|
||||
const uploading = ref(false)
|
||||
|
||||
const validateForm = () => {
|
||||
if (!formData.value.approvalId || isNaN(formData.value.approvalId)) {
|
||||
showConfirmDialog({ title: '错误', message: '审批单ID参数错误' })
|
||||
return false
|
||||
}
|
||||
if (formData.value.returnAmount <= 0) {
|
||||
showConfirmDialog({ title: '提示', message: '退款金额需大于0' })
|
||||
return false
|
||||
}
|
||||
if (null != approvalStore.currentApproval &&
|
||||
formData.value.returnAmount > approvalStore.currentApproval.goodsPrice) {
|
||||
showConfirmDialog({ title: '提示', message: '退款金额不能超过商品价格' })
|
||||
return false
|
||||
}
|
||||
|
||||
if (!formData.value.auditImages) {
|
||||
showConfirmDialog({ title: '提示', message: '请上传审核图片' })
|
||||
return false
|
||||
}
|
||||
if (formData.value.status === 3 && !formData.value.auditRemark) {
|
||||
showConfirmDialog({ title: '提示', message: '驳回时必须填写审核说明' })
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
const handleFileUpload = async (items: UploaderFileListItem | UploaderFileListItem[]) => {
|
||||
const files = Array.isArray(items) ? items : [items]
|
||||
uploading.value = true
|
||||
try {
|
||||
const uploadPromises = files.map(async (item) => {
|
||||
item.status = 'uploading'
|
||||
item.message = '上传中...'
|
||||
const file = item.file as File
|
||||
const formData = new FormData()
|
||||
formData.append('file', file)
|
||||
|
||||
const { data } = await axios.post<{
|
||||
code: number
|
||||
data: { url: string }
|
||||
message?: string
|
||||
}>(VITE_APP_BASE_API + '/file/upload', formData, {
|
||||
headers: { 'Content-Type': 'multipart/form-data' }
|
||||
})
|
||||
|
||||
if (data.code !== 0) {
|
||||
throw new Error(data.message || '文件上传失败')
|
||||
}
|
||||
return { url: data.data.url }
|
||||
})
|
||||
|
||||
const urls = await Promise.all(uploadPromises)
|
||||
files.forEach((item, index) => {
|
||||
item.status = 'done'
|
||||
item.message = '上传成功'
|
||||
item.url = urls[index].url
|
||||
})
|
||||
formData.value.auditImages = fileList.value.map(item => item.url).join(',')
|
||||
} catch (error) {
|
||||
showConfirmDialog({
|
||||
title: '上传失败',
|
||||
message: error instanceof Error ? error.message : '未知错误'
|
||||
})
|
||||
} finally {
|
||||
uploading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
const onStatusConfirm = ({ selectedOptions }: { selectedOptions: { value: number }[] }) => {
|
||||
submitting.value = true
|
||||
try {
|
||||
if (!selectedOptions?.[0]?.value) {
|
||||
throw new Error('请选择有效的审批状态')
|
||||
}
|
||||
formData.value.status = selectedOptions[0].value
|
||||
showStatusPicker.value = false
|
||||
} catch (error) {
|
||||
showConfirmDialog({
|
||||
title: '操作失败',
|
||||
message: error instanceof Error ? error.message : '状态选择异常'
|
||||
})
|
||||
} finally {
|
||||
submitting.value = false
|
||||
}
|
||||
}
|
||||
|
||||
const previewImage = (url: string) => {
|
||||
currentPreviewImage.value = url
|
||||
showPreview.value = true
|
||||
}
|
||||
onMounted(() => {
|
||||
if (!approvalStore.currentApproval) {
|
||||
router.push('/approval/list')
|
||||
} else if (approvalStore.currentApproval.status !== 1) {
|
||||
// 填充历史审批数据
|
||||
formData.value = {
|
||||
...formData.value,
|
||||
status: approvalStore.currentApproval.status,
|
||||
returnAmount: approvalStore.currentApproval.returnAmount,
|
||||
auditRemark: approvalStore.currentApproval.auditRemark,
|
||||
auditImages: approvalStore.currentApproval.auditImages
|
||||
}
|
||||
|
||||
// 处理文件回显
|
||||
if (approvalStore.currentApproval.auditImages) {
|
||||
fileList.value = approvalStore.currentApproval.auditImages.split(',').map(url => ({
|
||||
url,
|
||||
status: 'done',
|
||||
message: '已上传'
|
||||
}))
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
const handleSubmit = async () => {
|
||||
if (!validateForm()) return
|
||||
|
||||
submitting.value = true
|
||||
try {
|
||||
const { code, msg } = await handleApprovalApi(formData.value)
|
||||
|
||||
if (code === 0) {
|
||||
showSuccessToast('操作成功')
|
||||
await showConfirmDialog({
|
||||
title: "操作成功",
|
||||
message: `审批处理已完成`
|
||||
})
|
||||
router.push('/approval/list')
|
||||
} else {
|
||||
console.error('操作失败code:', code, 'msg:', msg)
|
||||
showConfirmDialog({
|
||||
title: '操作失败',
|
||||
message: msg || '操作失败'
|
||||
})
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('提交失败:', error)
|
||||
showConfirmDialog({
|
||||
title: '提交失败',
|
||||
message: error instanceof Error ? error.message : '网络请求异常'
|
||||
})
|
||||
} finally {
|
||||
submitting.value = false
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="approval-container">
|
||||
<van-nav-bar title="审批处理" left-text="返回" left-arrow fixed @click-left="() => router.go(-1)" />
|
||||
|
||||
<div class="content-wrapper">
|
||||
<van-cell-group>
|
||||
<van-cell title="商品名称" :value="approvalStore.currentApproval?.goodsName" />
|
||||
<van-cell title="商品封面" v-if="approvalStore.currentApproval?.coverImg">
|
||||
<van-image
|
||||
:src="approvalStore.currentApproval.coverImg"
|
||||
fit="cover"
|
||||
width="80"
|
||||
height="80"
|
||||
@click="previewImage(approvalStore.currentApproval.coverImg)"
|
||||
style="margin-top: 8px"
|
||||
/>
|
||||
</van-cell>
|
||||
<van-cell title="退还数量" :value="approvalStore.currentApproval?.returnQuantity" />
|
||||
<van-cell title="商品单价" :value="`¥${approvalStore.currentApproval?.goodsPrice}`" />
|
||||
<van-cell title="当前状态" :value="statusMap[approvalStore.currentApproval?.status || 1]" />
|
||||
<van-cell title="退还说明" :value="approvalStore.currentApproval?.returnRemark" />
|
||||
</van-cell-group>
|
||||
|
||||
<van-cell-group class="image-section">
|
||||
<van-cell title="退还凭证">
|
||||
<van-grid :column-num="3" gutter="10">
|
||||
<van-grid-item v-for="(img, index) in approvalStore.currentApproval?.returnImages.split(',')"
|
||||
:key="index">
|
||||
<van-image :src="img" fit="cover" @click="previewImage(img)" />
|
||||
</van-grid-item>
|
||||
</van-grid>
|
||||
</van-cell>
|
||||
</van-cell-group>
|
||||
|
||||
<van-cell-group>
|
||||
<!-- 原有表单字段保持不变 -->
|
||||
<van-field
|
||||
v-model="formData.returnAmount"
|
||||
:readonly="approvalStore.currentApproval?.status !== 1"
|
||||
label="退款金额"
|
||||
type="number"
|
||||
class="audit-remark-field"
|
||||
:min="0"
|
||||
/>
|
||||
<van-field
|
||||
:model-value="statusOptions.find(opt => opt.value === formData.status)?.text || ''"
|
||||
label="审批结果"
|
||||
readonly
|
||||
@click="showStatusPicker = true"
|
||||
:disabled="approvalStore.currentApproval?.status !== 1"
|
||||
class="clickable-status-field"
|
||||
/>
|
||||
<van-field
|
||||
v-model="formData.auditRemark"
|
||||
label="审核说明"
|
||||
type="textarea"
|
||||
rows="2"
|
||||
autosize
|
||||
class="audit-remark-field"
|
||||
/>
|
||||
</van-cell-group>
|
||||
|
||||
<van-popup v-model:show="showStatusPicker" position="bottom">
|
||||
<van-picker :columns="statusOptions" @confirm="onStatusConfirm" @cancel="showStatusPicker = false" />
|
||||
</van-popup>
|
||||
|
||||
<van-popup v-model:show="showPreview" position="center" :style="{ width: '90%', height: '80%' }" round>
|
||||
<div class="preview-wrapper">
|
||||
<van-icon name="cross" class="close-icon" @click="showPreview = false" />
|
||||
<van-image :src="currentPreviewImage" fit="contain" class="preview-image" />
|
||||
</div>
|
||||
</van-popup>
|
||||
|
||||
<van-cell-group class="upload-section">
|
||||
<van-cell title="审核凭证">
|
||||
<template #extra>
|
||||
<van-uploader v-model="fileList" multiple max-count="3" :after-read="handleFileUpload" />
|
||||
</template>
|
||||
</van-cell>
|
||||
</van-cell-group>
|
||||
|
||||
<div class="submit-bar"
|
||||
v-if="approvalStore.currentApproval?.status !== 2">
|
||||
<van-button
|
||||
type="primary"
|
||||
block
|
||||
:loading="submitting"
|
||||
loading-text="提交中..."
|
||||
@click="handleSubmit"
|
||||
>
|
||||
提交审批
|
||||
</van-button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
.approval-container {
|
||||
padding: 12px 16px;
|
||||
}
|
||||
|
||||
.content-wrapper {
|
||||
padding-top: 46px;
|
||||
}
|
||||
|
||||
.upload-section {
|
||||
margin: 20px 0;
|
||||
}
|
||||
|
||||
.preview-wrapper {
|
||||
position: relative;
|
||||
height: 100%;
|
||||
padding: 20px;
|
||||
|
||||
.close-icon {
|
||||
position: absolute;
|
||||
top: 10px;
|
||||
right: 10px;
|
||||
z-index: 1;
|
||||
font-size: 24px;
|
||||
color: #fff;
|
||||
background: rgba(0, 0, 0, 0.3);
|
||||
border-radius: 50%;
|
||||
padding: 4px;
|
||||
}
|
||||
|
||||
.preview-image {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
.submit-bar {
|
||||
position: sticky;
|
||||
bottom: 20px;
|
||||
padding: 16px;
|
||||
background: #fff;
|
||||
box-shadow: 0 -2px 12px rgba(0, 0, 0, 0.1);
|
||||
border-radius: 8px;
|
||||
margin: 0 16px;
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
.content-wrapper {
|
||||
padding-bottom: 100px;
|
||||
}
|
||||
|
||||
.audit-remark-field::v-deep .van-field__control {
|
||||
background-color: #fffbe6;
|
||||
padding: 8px;
|
||||
border-radius: 4px;
|
||||
}
|
||||
|
||||
.clickable-status-field:not(:disabled)::v-deep .van-field__control {
|
||||
cursor: pointer;
|
||||
transition: all 0.3s ease;
|
||||
background-color: #f7f8fa;
|
||||
}
|
||||
|
||||
.clickable-status-field:not(:disabled):hover::v-deep .van-field__control {
|
||||
background-color: #f2f3f5;
|
||||
box-shadow: 0 2px 6px rgba(0, 0, 0, 0.1);
|
||||
}
|
||||
|
||||
.clickable-status-field:not(:disabled):active::v-deep .van-field__control {
|
||||
background-color: #ebedf0;
|
||||
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.2);
|
||||
}
|
||||
</style>
|
|
@ -0,0 +1,192 @@
|
|||
<template>
|
||||
<div class="approval-list-container">
|
||||
<!-- 搜索表单 -->
|
||||
<van-form @submit="handleSearch">
|
||||
<van-field v-model="searchParams.approvalId" label="审批单号" type="number" placeholder="请输入审批单号" />
|
||||
|
||||
<van-field v-model="searchParams.orderId" label="订单编号" type="number" placeholder="请输入订单编号" />
|
||||
|
||||
<van-field v-model="searchParams.goodsId" label="商品ID" type="number" placeholder="请输入商品ID" />
|
||||
|
||||
<van-field name="status" label="审批状态" readonly clickable v-model="statusText" placeholder="请选择状态"
|
||||
@click="showStatusPicker = true" />
|
||||
<van-popup v-model:show="showStatusPicker" position="bottom">
|
||||
<van-picker :columns="statusOptions" @confirm="onStatusConfirm" @cancel="showStatusPicker = false" />
|
||||
</van-popup>
|
||||
|
||||
<!-- <van-field
|
||||
readonly
|
||||
clickable
|
||||
name="date"
|
||||
:value="dateRangeText"
|
||||
label="申请时间"
|
||||
placeholder="选择时间范围"
|
||||
@click="showDatePicker = true"
|
||||
/>
|
||||
<van-popup v-model:show="showDatePicker" position="bottom">
|
||||
<van-datetime-picker
|
||||
type="daterange"
|
||||
@confirm="onDateConfirm"
|
||||
@cancel="showDatePicker = false"
|
||||
/>
|
||||
</van-popup> -->
|
||||
|
||||
<div style="margin: 16px;">
|
||||
<van-button block type="primary" native-type="submit">搜索</van-button>
|
||||
<van-button block plain type="primary" style="margin-top: 10px;" @click="handleReset">重置</van-button>
|
||||
</div>
|
||||
</van-form>
|
||||
|
||||
<!-- 审批列表 -->
|
||||
<van-list v-model:loading="loading" :finished="finished" finished-text="没有更多了" @load="onLoad">
|
||||
<van-cell v-for="item in list" :key="item.approvalId" :title="`审批单号:${item.approvalId}`" clickable
|
||||
@click="handleCellClick(item.approvalId)">
|
||||
<template #label>
|
||||
<div>商品名称:{{ item.goodsName }}</div>
|
||||
<div>申请时间:{{ item.createTime }}</div>
|
||||
<van-tag :type="statusTagType(item.status)">
|
||||
{{ statusMap[item.status] }}
|
||||
</van-tag>
|
||||
</template>
|
||||
</van-cell>
|
||||
</van-list>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { ref, reactive } from 'vue'
|
||||
import { getApprovalListApi } from '@/common/apis/approval'
|
||||
import type { SearchApiReturnApprovalQuery, ReturnApprovalEntity } from '@/common/apis/approval/type'
|
||||
import type { PickerConfirmEventParams } from 'vant/es';
|
||||
import { useApprovalStore } from '@/pinia/stores/approval';
|
||||
|
||||
const router = useRouter()
|
||||
|
||||
// 搜索参数
|
||||
const searchParams = reactive<SearchApiReturnApprovalQuery>({
|
||||
pageNum: 1,
|
||||
pageSize: 10,
|
||||
})
|
||||
|
||||
// 状态选择相关
|
||||
const showStatusPicker = ref(false)
|
||||
const statusOptions = [
|
||||
{ text: '全部', value: undefined },
|
||||
{ text: '待审核', value: 1 },
|
||||
{ text: '已通过', value: 2 },
|
||||
{ text: '已驳回', value: 3 },
|
||||
]
|
||||
|
||||
const statusMap: { [key: number]: string } = {
|
||||
1: '待审核',
|
||||
2: '已通过',
|
||||
3: '已驳回'
|
||||
}
|
||||
|
||||
const statusText = ref('')
|
||||
|
||||
// 时间选择相关
|
||||
const showDatePicker = ref(false)
|
||||
const dateRangeText = ref('')
|
||||
|
||||
// 列表相关
|
||||
const list = ref<ReturnApprovalEntity[]>([])
|
||||
const loading = ref(false)
|
||||
const finished = ref(false)
|
||||
|
||||
const handleCellClick = (approvalId: number) => {
|
||||
const approvalStore = useApprovalStore()
|
||||
const currentItem = list.value.find(item => item.approvalId === approvalId)
|
||||
if (currentItem) {
|
||||
approvalStore.setCurrentApproval(currentItem)
|
||||
}
|
||||
router.push(`/approval/handle/${approvalId}`)
|
||||
}
|
||||
|
||||
// 状态标签类型
|
||||
const statusTagType = (status: number) => {
|
||||
switch (status) {
|
||||
case 1: return 'warning'
|
||||
case 2: return 'success'
|
||||
case 3: return 'danger'
|
||||
default: return 'default'
|
||||
}
|
||||
}
|
||||
|
||||
// 处理状态选择
|
||||
const onStatusConfirm = (e: PickerConfirmEventParams) => {
|
||||
const { selectedOptions } = e;
|
||||
searchParams.status = selectedOptions[0]?.value ? Number(selectedOptions[0]?.value) : undefined;
|
||||
showStatusPicker.value = false;
|
||||
// 确保赋值给 statusText 的是字符串类型
|
||||
statusText.value = String(selectedOptions[0]?.text || '');
|
||||
}
|
||||
|
||||
// 处理时间选择
|
||||
const onDateConfirm = (values: Date[]) => {
|
||||
const [start, end] = values
|
||||
searchParams.startTime = start.toISOString().split('T')[0]
|
||||
searchParams.endTime = end.toISOString().split('T')[0]
|
||||
dateRangeText.value = `${searchParams.startTime} 至 ${searchParams.endTime}`
|
||||
showDatePicker.value = false
|
||||
}
|
||||
|
||||
// 搜索处理
|
||||
const handleSearch = () => {
|
||||
list.value = []
|
||||
searchParams.pageNum = 1
|
||||
onLoad()
|
||||
}
|
||||
|
||||
// 重置表单
|
||||
const handleReset = () => {
|
||||
Object.assign(searchParams, {
|
||||
pageNum: 1,
|
||||
pageSize: 10,
|
||||
approvalId: undefined,
|
||||
orderId: undefined,
|
||||
goodsId: undefined,
|
||||
status: undefined,
|
||||
startTime: undefined,
|
||||
endTime: undefined
|
||||
})
|
||||
statusText.value = ''
|
||||
dateRangeText.value = ''
|
||||
handleSearch()
|
||||
}
|
||||
|
||||
// 加载数据
|
||||
const onLoad = async () => {
|
||||
try {
|
||||
const { data } = await getApprovalListApi(searchParams)
|
||||
list.value.push(...data.rows)
|
||||
loading.value = false
|
||||
|
||||
if (list.value.length >= data.total) {
|
||||
finished.value = true
|
||||
} else {
|
||||
searchParams.pageNum++
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('获取审批列表失败', error)
|
||||
finished.value = true
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.approval-list-container {
|
||||
padding: 12px;
|
||||
}
|
||||
|
||||
.van-cell__title {
|
||||
font-size: 14px;
|
||||
color: #333;
|
||||
}
|
||||
|
||||
.van-cell__label {
|
||||
margin-top: 8px;
|
||||
color: #666;
|
||||
font-size: 12px;
|
||||
}
|
||||
</style>
|
|
@ -13,7 +13,8 @@ const route = useRoute()
|
|||
const formData = ref<SubmitApprovalRequestData>({
|
||||
orderGoodsId: Number(route.query.orderGoodsId),
|
||||
returnQuantity: 1,
|
||||
returnImages: ''
|
||||
returnImages: '',
|
||||
returnRemark: ''
|
||||
})
|
||||
|
||||
watch(() => route.query.orderGoodsId, (newVal) => {
|
||||
|
@ -71,10 +72,9 @@ const handleFileUpload = async (items: UploaderFileListItem | UploaderFileListIt
|
|||
const urls = await Promise.all(uploadPromises)
|
||||
files.forEach((item, index) => {
|
||||
item.status = 'done'
|
||||
item.message = ''
|
||||
item.message = '上传成功'
|
||||
item.url = urls[index].url
|
||||
})
|
||||
showToast('上传成功')
|
||||
} catch (error) {
|
||||
showConfirmDialog({
|
||||
title: '上传失败',
|
||||
|
@ -96,7 +96,13 @@ const handleSubmit = async () => {
|
|||
|
||||
if (code === 0) {
|
||||
showSuccessToast('提交成功')
|
||||
router.push('/order/' + orderId)
|
||||
try {
|
||||
await showConfirmDialog({
|
||||
title: "提交成功",
|
||||
message: `退货申请已提交,等待管理员审核`
|
||||
})
|
||||
} catch (error) { }
|
||||
router.push('/order/' + orderId.value)
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('提交失败:', error)
|
||||
|
@ -118,6 +124,7 @@ const handleSubmit = async () => {
|
|||
<van-cell-group>
|
||||
<!-- 移除订单ID和商品ID的输入框 -->
|
||||
<van-field v-model="formData.returnQuantity" label="退还数量" type="number" :min="1" />
|
||||
<van-field v-model="formData.returnRemark" label="退货备注" type="textarea" rows="2" autosize />
|
||||
</van-cell-group>
|
||||
|
||||
<van-cell-group class="upload-section">
|
||||
|
|
|
@ -251,7 +251,6 @@ loadCabinetDetail()
|
|||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: space-between;
|
||||
height: 100px;
|
||||
position: relative;
|
||||
padding-left: 3px;
|
||||
}
|
||||
|
|
|
@ -0,0 +1,135 @@
|
|||
<template>
|
||||
<div class="login-container">
|
||||
<van-form @submit="handleSubmit">
|
||||
<van-field
|
||||
v-model="form.tel"
|
||||
name="手机号"
|
||||
label="手机号"
|
||||
placeholder="请输入手机号"
|
||||
:rules="[{ required: true, message: '请填写手机号' }, { pattern: /^1[3-9]\d{9}$/, message: '手机号格式错误' }]"
|
||||
/>
|
||||
|
||||
<van-field
|
||||
v-model="form.vcode"
|
||||
center
|
||||
clearable
|
||||
name="验证码"
|
||||
label="验证码"
|
||||
placeholder="请输入验证码"
|
||||
:rules="[{ required: true, message: '请填写验证码' }]"
|
||||
>
|
||||
<template #button>
|
||||
<van-button
|
||||
size="small"
|
||||
:disabled="countdown > 0"
|
||||
@click="sendSms"
|
||||
native-type="button"
|
||||
>
|
||||
{{ countdown > 0 ? `${countdown}秒后重试` : '获取验证码' }}
|
||||
</van-button>
|
||||
</template>
|
||||
</van-field>
|
||||
|
||||
<div style="margin: 16px;">
|
||||
<van-button round block type="primary" native-type="submit">
|
||||
立即登录
|
||||
</van-button>
|
||||
</div>
|
||||
</van-form>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ref, onMounted } from 'vue'
|
||||
import { useRouter } from 'vue-router'
|
||||
import { showSuccessToast, showFailToast } from 'vant'
|
||||
import { getTokenApi, sendSmsApi, verifySmsApi } from '@/common/apis/ab98'
|
||||
import { useAb98UserStore } from '@/pinia/stores/ab98-user'
|
||||
|
||||
const userStore = useAb98UserStore()
|
||||
const router = useRouter()
|
||||
|
||||
const form = ref({
|
||||
tel: '',
|
||||
vcode: ''
|
||||
})
|
||||
|
||||
const countdown = ref(0)
|
||||
const loading = ref(true)
|
||||
let timer: number | null = null
|
||||
|
||||
onMounted(async () => {
|
||||
try {
|
||||
const { data } = await getTokenApi('ab98_app')
|
||||
if (data.token) {
|
||||
userStore.setToken(data.token)
|
||||
} else {
|
||||
showFailToast('令牌获取失败')
|
||||
}
|
||||
} catch (err) {
|
||||
showFailToast('网络异常,请重试')
|
||||
} finally {
|
||||
loading.value = false
|
||||
}
|
||||
})
|
||||
|
||||
const sendSms = async () => {
|
||||
try {
|
||||
if (!/^1[3-9]\d{9}$/.test(form.value.tel)) {
|
||||
showFailToast('手机号格式错误')
|
||||
return
|
||||
}
|
||||
|
||||
const { data } = await sendSmsApi(userStore.token, form.value.tel)
|
||||
if (data.success) {
|
||||
startCountdown()
|
||||
showSuccessToast('验证码已发送')
|
||||
} else {
|
||||
showFailToast(data.message || '发送失败')
|
||||
}
|
||||
} catch (err) {
|
||||
showFailToast('请求异常,请稍后重试')
|
||||
}
|
||||
}
|
||||
|
||||
const startCountdown = () => {
|
||||
countdown.value = 60
|
||||
timer = window.setInterval(() => {
|
||||
if (countdown.value <= 0 && timer) {
|
||||
window.clearInterval(timer)
|
||||
return
|
||||
}
|
||||
countdown.value--
|
||||
}, 1000)
|
||||
}
|
||||
|
||||
const handleSubmit = async () => {
|
||||
try {
|
||||
const { data } = await verifySmsApi({
|
||||
token: userStore.token,
|
||||
tel: form.value.tel,
|
||||
vcode: form.value.vcode
|
||||
})
|
||||
|
||||
if (data.success) {
|
||||
userStore.setTel(form.value.tel)
|
||||
userStore.setUserInfo(data)
|
||||
userStore.setIsLogin(true)
|
||||
showSuccessToast('登录成功')
|
||||
router.push('/')
|
||||
} else {
|
||||
showFailToast('验证码错误')
|
||||
}
|
||||
} catch (err) {
|
||||
console.error(err)
|
||||
showFailToast('登录失败,请稍后重试')
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.login-container {
|
||||
padding: 20px;
|
||||
margin-top: 30%;
|
||||
}
|
||||
</style>
|
|
@ -1,17 +1,22 @@
|
|||
<script setup lang="ts">
|
||||
import { useRouter } from 'vue-router'
|
||||
import { useWxStore } from '@/pinia/stores/wx'
|
||||
import { computed } from 'vue'
|
||||
import { useAb98UserStore } from '@/pinia/stores/ab98-user'
|
||||
import { storeToRefs } from 'pinia'
|
||||
import { publicPath } from "@/common/utils/path"
|
||||
|
||||
const router = useRouter()
|
||||
const wxStore = useWxStore()
|
||||
const balance = computed(() => wxStore.balance)
|
||||
const ab98UserStore = useAb98UserStore()
|
||||
|
||||
const { balance } = storeToRefs(wxStore)
|
||||
const { name: userName, sex: userSex, face_img } = storeToRefs(ab98UserStore)
|
||||
|
||||
const userAvatar = face_img.value ? face_img.value : `${publicPath}img/1.jpg`
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div un-py-16px>
|
||||
<!-- 用户信息区域 -->
|
||||
<van-cell-group class="user-card">
|
||||
<van-cell :border="false">
|
||||
<template #title>
|
||||
|
@ -20,13 +25,12 @@ const balance = computed(() => wxStore.balance)
|
|||
round
|
||||
width="80"
|
||||
height="80"
|
||||
:src="`${publicPath}img/1.jpg`"
|
||||
:src="userAvatar"
|
||||
class="mr-4"
|
||||
/>
|
||||
<div>
|
||||
<div class="text-lg font-bold mb-2">{{ '' }}</div>
|
||||
<van-tag type="primary" class="mr-2">{{ 20 }}岁</van-tag>
|
||||
<van-tag type="success">{{ '男' }}</van-tag>
|
||||
<div class="text-lg font-bold mb-2">{{ userName }}</div>
|
||||
<van-tag type="primary" class="mr-2">{{ userSex }}</van-tag>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
@ -75,6 +79,7 @@ const balance = computed(() => wxStore.balance)
|
|||
<van-cell-group>
|
||||
<van-cell title="订单列表" is-link @click="router.push('/order-list')" />
|
||||
<van-cell title="柜机管理" is-link @click="router.push('/cabinet')" v-if="wxStore.isCabinetAdmin"/>
|
||||
<van-cell title="审批中心" is-link @click="router.push('/approval/list')" v-if="wxStore.isCabinetAdmin"/>
|
||||
</van-cell-group>
|
||||
</div>
|
||||
</template>
|
||||
|
|
|
@ -20,7 +20,7 @@ async function handleOpenCabinet(orderId: number, orderGoodsId: number) {
|
|||
try {
|
||||
const result = await openCabinetApi(orderId, orderGoodsId)
|
||||
if (result.code !== 0) {
|
||||
showFailToast(result.message)
|
||||
showFailToast(result.msg || '开启失败,请稍后重试')
|
||||
return
|
||||
}
|
||||
showSuccessToast('柜口已成功开启')
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
<script setup lang="ts">
|
||||
import { useCartStore } from "@/pinia/stores/cart"
|
||||
import { useWxStore } from "@/pinia/stores/wx"
|
||||
import { useAb98UserStore } from '@/pinia/stores/ab98-user'
|
||||
import { storeToRefs } from "pinia"
|
||||
import { showConfirmDialog } from "vant"
|
||||
import { submitOrderApi } from "@/common/apis/shop"
|
||||
|
@ -13,7 +14,10 @@ const cartStore = useCartStore()
|
|||
const { cartItems, totalPrice } = storeToRefs(cartStore)
|
||||
|
||||
const wxStore = useWxStore()
|
||||
const { openid, balance } = storeToRefs(wxStore)
|
||||
const { openid, balance, corpid, userid: qyUserid } = storeToRefs(wxStore)
|
||||
|
||||
const ab98UserStore = useAb98UserStore()
|
||||
const { tel, userid: ab98Userid } = storeToRefs(ab98UserStore)
|
||||
|
||||
const selectedPayment = ref<'wechat' | 'balance'>('wechat')
|
||||
const contact = ref("")
|
||||
|
@ -72,6 +76,11 @@ async function handleSubmit() {
|
|||
|
||||
submitting.value = true
|
||||
try {
|
||||
// 判断用户类型:
|
||||
// 2 - 企业微信用户(corpid存在)
|
||||
// 1 - 汇邦云用户(qyUserid存在)
|
||||
// 0 - 外部用户
|
||||
const isInternal = corpid.value ? 2 : qyUserid.value ? 1 : 0;
|
||||
const requestData: SubmitOrderRequestData = {
|
||||
openid: openid.value,
|
||||
userid: wxStore.userid,
|
||||
|
@ -80,7 +89,10 @@ async function handleSubmit() {
|
|||
goodsId: item.product.id,
|
||||
quantity: item.quantity
|
||||
})),
|
||||
paymentType: selectedPayment.value
|
||||
paymentType: selectedPayment.value,
|
||||
mobile: tel.value,
|
||||
qyUserid: isInternal === 2 ? qyUserid.value : ab98Userid.value,
|
||||
isInternal: isInternal
|
||||
}
|
||||
|
||||
const { code, data } = await submitOrderApi(requestData)
|
||||
|
@ -155,7 +167,7 @@ async function handleSubmit() {
|
|||
<van-field label="支付方式" :model-value="selectedPayment" readonly>
|
||||
<template #input>
|
||||
<van-radio-group v-model="selectedPayment" direction="horizontal">
|
||||
<van-radio name="wechat">
|
||||
<van-radio name="wechat" v-if="!wxStore.corpid">
|
||||
<van-icon name="wechat" class="method-icon" />
|
||||
微信支付
|
||||
</van-radio>
|
||||
|
|
|
@ -0,0 +1,123 @@
|
|||
import { pinia } from "@/pinia"
|
||||
import { LoginData } from "@/common/apis/ab98/type"
|
||||
|
||||
// 本地存储键名常量
|
||||
const STORAGE_KEYS = {
|
||||
FACE: 'ab98_face',
|
||||
SEX: 'ab98_sex',
|
||||
NAME: 'ab98_name',
|
||||
USERID: 'ab98_userid',
|
||||
REGISTERED: 'ab98_registered',
|
||||
TEL: 'ab98_tel',
|
||||
TOKEN: 'ab98_token'
|
||||
}
|
||||
|
||||
/**
|
||||
* AB98用户信息存储
|
||||
* @description 管理AB98系统用户相关状态信息
|
||||
*/
|
||||
export const useAb98UserStore = defineStore("ab98User", () => {
|
||||
// 用户面部图像URL
|
||||
const storedFace = localStorage.getItem(STORAGE_KEYS.FACE)
|
||||
const face_img = ref<string>(storedFace ? decodeURIComponent(storedFace) : '')
|
||||
// 用户性别(男/女)
|
||||
const storedSex = localStorage.getItem(STORAGE_KEYS.SEX)
|
||||
const sex = ref<string>(storedSex ? decodeURIComponent(storedSex) : '')
|
||||
// 用户真实姓名
|
||||
const storedName = localStorage.getItem(STORAGE_KEYS.NAME)
|
||||
const name = ref<string>(storedName ? decodeURIComponent(storedName) : '')
|
||||
// AB98系统用户唯一标识
|
||||
const storedUserId = localStorage.getItem(STORAGE_KEYS.USERID)
|
||||
const userid = ref<string>(storedUserId ? decodeURIComponent(storedUserId) : "")
|
||||
// 是否已完成注册流程
|
||||
const registered = ref<boolean>(JSON.parse(localStorage.getItem(STORAGE_KEYS.REGISTERED) || "false"))
|
||||
// 用户绑定手机号
|
||||
const storedTel = localStorage.getItem(STORAGE_KEYS.TEL)
|
||||
const tel = ref<string>(storedTel ? decodeURIComponent(storedTel) : "")
|
||||
// 用户认证令牌
|
||||
const storedToken = localStorage.getItem(STORAGE_KEYS.TOKEN)
|
||||
const token = ref<string>(storedToken ? decodeURIComponent(storedToken) : "")
|
||||
// 用户登录状态
|
||||
const isLogin = ref<boolean>(false);
|
||||
isLogin.value = tel.value ? true : false;
|
||||
|
||||
/**
|
||||
* 更新用户基本信息
|
||||
* @param data - 登录接口返回的用户数据
|
||||
*/
|
||||
const setUserInfo = (data: LoginData) => {
|
||||
face_img.value = data.face_img
|
||||
localStorage.setItem(STORAGE_KEYS.FACE, encodeURIComponent(data.face_img))
|
||||
sex.value = data.sex
|
||||
localStorage.setItem(STORAGE_KEYS.SEX, encodeURIComponent(data.sex))
|
||||
name.value = data.name
|
||||
localStorage.setItem(STORAGE_KEYS.NAME, encodeURIComponent(data.name))
|
||||
userid.value = data.userid
|
||||
localStorage.setItem(STORAGE_KEYS.USERID, encodeURIComponent(data.userid))
|
||||
registered.value = data.registered
|
||||
localStorage.setItem(STORAGE_KEYS.REGISTERED, JSON.stringify(data.registered))
|
||||
tel.value = data.tel
|
||||
localStorage.setItem(STORAGE_KEYS.TEL, encodeURIComponent(data.tel))
|
||||
}
|
||||
|
||||
/**
|
||||
* 清空用户敏感信息
|
||||
* @description 用于用户登出或会话过期时
|
||||
*/
|
||||
const clearUserInfo = () => {
|
||||
face_img.value = ""
|
||||
localStorage.removeItem(STORAGE_KEYS.FACE)
|
||||
sex.value = ""
|
||||
localStorage.removeItem(STORAGE_KEYS.SEX)
|
||||
name.value = ""
|
||||
localStorage.removeItem(STORAGE_KEYS.NAME)
|
||||
userid.value = ""
|
||||
localStorage.removeItem(STORAGE_KEYS.USERID)
|
||||
registered.value = false
|
||||
localStorage.removeItem(STORAGE_KEYS.REGISTERED)
|
||||
tel.value = ""
|
||||
localStorage.removeItem(STORAGE_KEYS.TEL)
|
||||
localStorage.removeItem(STORAGE_KEYS.TOKEN)
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置认证令牌
|
||||
* @param value - JWT格式的认证令牌
|
||||
*/
|
||||
const setToken = (value: string) => {
|
||||
localStorage.setItem(STORAGE_KEYS.TOKEN, encodeURIComponent(value))
|
||||
token.value = value
|
||||
}
|
||||
|
||||
const setTel = (value: string) => {
|
||||
localStorage.setItem(STORAGE_KEYS.TEL, btoa(value))
|
||||
tel.value = value
|
||||
}
|
||||
|
||||
const setIsLogin = (value: boolean) => {
|
||||
isLogin.value = value;
|
||||
}
|
||||
|
||||
return {
|
||||
face_img,
|
||||
sex,
|
||||
name,
|
||||
userid,
|
||||
registered,
|
||||
tel,
|
||||
token,
|
||||
isLogin,
|
||||
setUserInfo,
|
||||
setToken,
|
||||
setTel,
|
||||
setIsLogin,
|
||||
clearUserInfo
|
||||
}
|
||||
})
|
||||
|
||||
/**
|
||||
* @description 在非setup上下文或SSR场景中使用store
|
||||
*/
|
||||
export function useAb98UserStoreOutside() {
|
||||
return useAb98UserStore(pinia)
|
||||
}
|
|
@ -0,0 +1,25 @@
|
|||
import { defineStore } from 'pinia'
|
||||
import { ref } from 'vue'
|
||||
import type { ReturnApprovalEntity } from '@/common/apis/approval/type'
|
||||
|
||||
export interface ApprovalDetail extends ReturnApprovalEntity {
|
||||
goodsName: string
|
||||
coverImg: string
|
||||
}
|
||||
|
||||
export const useApprovalStore = defineStore('approval', () => {
|
||||
const currentApproval = ref<ApprovalDetail | null>(null)
|
||||
|
||||
const setCurrentApproval = (approval: ApprovalDetail) => {
|
||||
currentApproval.value = approval
|
||||
}
|
||||
|
||||
return {
|
||||
currentApproval,
|
||||
setCurrentApproval
|
||||
}
|
||||
})
|
||||
|
||||
export function useApprovalStoreOutside() {
|
||||
return useApprovalStore()
|
||||
}
|
|
@ -5,18 +5,34 @@ import { isWhiteList } from "@/router/whitelist"
|
|||
import { useTitle } from "@@/composables/useTitle"
|
||||
import { getToken } from "@@/utils/cache/cookies"
|
||||
import NProgress from "nprogress"
|
||||
import { useAb98UserStore } from '@/pinia/stores/ab98-user'
|
||||
|
||||
|
||||
NProgress.configure({ showSpinner: false })
|
||||
|
||||
const { setTitle } = useTitle()
|
||||
|
||||
const LOGIN_PATH = "/login"
|
||||
const LOGIN_PATH = "/ab98"
|
||||
|
||||
export function registerNavigationGuard(router: Router) {
|
||||
// 全局前置守卫
|
||||
router.beforeEach((to, _from) => {
|
||||
NProgress.start()
|
||||
|
||||
// 企业微信登录
|
||||
const urlParams = new URLSearchParams(window.location.search);
|
||||
const corpid = urlParams.get('corpid') || undefined;
|
||||
if (corpid) {
|
||||
return true;
|
||||
}
|
||||
|
||||
const userStore = useAb98UserStore()
|
||||
if (!userStore.isLogin) {
|
||||
// 如果在免登录的白名单中,则直接进入
|
||||
if (isWhiteList(to)) return true
|
||||
// 其他没有访问权限的页面将被重定向到登录页面
|
||||
return LOGIN_PATH
|
||||
}
|
||||
return true;
|
||||
// const userStore = useUserStore()
|
||||
// // 如果没有登录
|
||||
|
|
|
@ -34,6 +34,11 @@ export const routes: RouteRecordRaw[] = [
|
|||
component: () => import('@/pages/approval/submit.vue'),
|
||||
meta: { requiresAuth: true }
|
||||
},
|
||||
{
|
||||
path: '/approval/handle/:approvalId',
|
||||
component: () => import('@/pages/approval/handle.vue'),
|
||||
meta: { requiresAuth: true }
|
||||
},
|
||||
{
|
||||
path: '/order-success',
|
||||
name: 'OrderSuccess',
|
||||
|
@ -75,6 +80,25 @@ export const routes: RouteRecordRaw[] = [
|
|||
meta: {
|
||||
title: '柜机管理',
|
||||
keepAlive: true,
|
||||
layout: {
|
||||
navBar: {
|
||||
showNavBar: false,
|
||||
showLeftArrow: false
|
||||
},
|
||||
tabbar: {
|
||||
showTabbar: true,
|
||||
icon: "home-o"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
path: '/approval/list',
|
||||
component: () => import('@/pages/approval/list.vue'),
|
||||
name: "Approval",
|
||||
meta: {
|
||||
title: '审批中心',
|
||||
keepAlive: true,
|
||||
layout: {
|
||||
navBar: {
|
||||
showNavBar: false,
|
||||
|
@ -123,6 +147,14 @@ export const routes: RouteRecordRaw[] = [
|
|||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
path: "/ab98",
|
||||
component: () => import("@/pages/login/Ab98Login.vue"),
|
||||
name: "Ab98Login",
|
||||
meta: {
|
||||
title: "登录"
|
||||
}
|
||||
}
|
||||
]
|
||||
|
||||
|
@ -132,6 +164,11 @@ export const routes: RouteRecordRaw[] = [
|
|||
component: () => import('@/pages/approval/submit.vue'),
|
||||
meta: { requiresAuth: true }
|
||||
},
|
||||
{
|
||||
path: '/approval/handle/:approvalId',
|
||||
component: () => import('@/pages/approval/handle.vue'),
|
||||
meta: { requiresAuth: true }
|
||||
},
|
||||
{
|
||||
path: '/order-success',
|
||||
name: 'OrderSuccess',
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import type { RouteLocationNormalizedGeneric, RouteRecordNameGeneric } from "vue-router"
|
||||
|
||||
/** 免登录白名单(匹配路由 path) */
|
||||
const whiteListByPath: string[] = ["/login"]
|
||||
const whiteListByPath: string[] = ["/login", "/ab98"]
|
||||
|
||||
/** 免登录白名单(匹配路由 name) */
|
||||
const whiteListByName: RouteRecordNameGeneric[] = []
|
||||
|
|
|
@ -2,11 +2,11 @@
|
|||
interface ApiResponseData<T> {
|
||||
code: number
|
||||
data: T
|
||||
message: string
|
||||
msg: string
|
||||
}
|
||||
|
||||
interface ApiResponseMsgData<T> {
|
||||
code: number
|
||||
data: T
|
||||
message: string
|
||||
msg: string
|
||||
}
|
|
@ -17,12 +17,16 @@ declare module 'vue' {
|
|||
VanConfigProvider: typeof import('vant/es')['ConfigProvider']
|
||||
VanDivider: typeof import('vant/es')['Divider']
|
||||
VanField: typeof import('vant/es')['Field']
|
||||
VanForm: typeof import('vant/es')['Form']
|
||||
VanGrid: typeof import('vant/es')['Grid']
|
||||
VanGridItem: typeof import('vant/es')['GridItem']
|
||||
VanIcon: typeof import('vant/es')['Icon']
|
||||
VanImage: typeof import('vant/es')['Image']
|
||||
VanList: typeof import('vant/es')['List']
|
||||
VanLoading: typeof import('vant/es')['Loading']
|
||||
VanNavBar: typeof import('vant/es')['NavBar']
|
||||
VanPicker: typeof import('vant/es')['Picker']
|
||||
VanPopup: typeof import('vant/es')['Popup']
|
||||
VanRadio: typeof import('vant/es')['Radio']
|
||||
VanRadioGroup: typeof import('vant/es')['RadioGroup']
|
||||
VanSidebar: typeof import('vant/es')['Sidebar']
|
||||
|
|
Loading…
Reference in New Issue