feat(mini): add ETC vehicle recharge apply for drivers and escorts
Add menu SQL, workbench entry, mineVehicles API client, and list/form pages styled like fuel register. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
1 parent
48aef9f233
commit
c70b17f8ca
8 files changed
+1149
-2
No files matched your search
@@ -0,0 +1,89 @@
|
||||
-- 小程序:运输管理 → ETC加油充值申请(角色「司机」「押运员」)
|
||||
-- 可重复执行(NOT EXISTS 防重)
|
||||
SET NAMES utf8mb4;
|
||||
|
||||
-- 测试库补角色(生产已有则跳过)
|
||||
INSERT INTO `sys_role` (
|
||||
`id`, `role_name`, `data_scope`, `status`, `tenant_no`, `order_num`, `remark`,
|
||||
`create_by`, `create_dept_id`, `create_time`, `update_by`, `update_time`, `del_flag`
|
||||
)
|
||||
SELECT
|
||||
'MINI_ROLE_DRIVER', '司机', '1', '1', 'shanxia2.0', 60, '小程序司机端',
|
||||
'system', '', NOW(), NULL, NOW(), 0
|
||||
FROM DUAL
|
||||
WHERE NOT EXISTS (
|
||||
SELECT 1 FROM `sys_role` WHERE `role_name` = '司机' AND `del_flag` = 0
|
||||
);
|
||||
|
||||
INSERT INTO `sys_role` (
|
||||
`id`, `role_name`, `data_scope`, `status`, `tenant_no`, `order_num`, `remark`,
|
||||
`create_by`, `create_dept_id`, `create_time`, `update_by`, `update_time`, `del_flag`
|
||||
)
|
||||
SELECT
|
||||
'MINI_ROLE_ESCORT', '押运员', '1', '1', 'shanxia2.0', 61, '小程序押运端',
|
||||
'system', '', NOW(), NULL, NOW(), 0
|
||||
FROM DUAL
|
||||
WHERE NOT EXISTS (
|
||||
SELECT 1 FROM `sys_role` WHERE `role_name` = '押运员' AND `del_flag` = 0
|
||||
);
|
||||
|
||||
INSERT INTO `sys_menu` (
|
||||
`id`, `menu_name`, `parent_id`, `menu_type`, `path`, `component`, `perms`,
|
||||
`is_frame`, `visible`, `status`, `tenant_no`, `order_num`, `remark`,
|
||||
`create_by`, `create_dept_id`, `create_time`, `update_by`, `update_time`, `del_flag`
|
||||
)
|
||||
SELECT
|
||||
'MINI_PL_ROOT', '运输管理', '1', 'M', '/mini/pl', NULL, NULL,
|
||||
1, '1', '1', 'shanxia2.0', 4, '小程序运输管理',
|
||||
'system', '', NOW(), NULL, NOW(), 0
|
||||
FROM DUAL
|
||||
WHERE NOT EXISTS (
|
||||
SELECT 1 FROM `sys_menu` WHERE `id` = 'MINI_PL_ROOT' AND `del_flag` = 0
|
||||
);
|
||||
|
||||
INSERT INTO `sys_menu` (
|
||||
`id`, `menu_name`, `parent_id`, `menu_type`, `path`, `component`, `perms`,
|
||||
`is_frame`, `visible`, `status`, `tenant_no`, `order_num`, `remark`,
|
||||
`create_by`, `create_dept_id`, `create_time`, `update_by`, `update_time`, `del_flag`
|
||||
)
|
||||
SELECT
|
||||
'MINI_PL_VEHICLE_RECHARGE_APPLY', 'ETC加油充值申请', 'MINI_PL_ROOT', 'C',
|
||||
'vehicle-recharge-apply', NULL,
|
||||
'mini:pl:vehicleRechargeApply:list',
|
||||
1, '1', '1', 'shanxia2.0', 2, '小程序司机/押运 ETC加油充值申请',
|
||||
'system', '', NOW(), NULL, NOW(), 0
|
||||
FROM DUAL
|
||||
WHERE NOT EXISTS (
|
||||
SELECT 1 FROM `sys_menu` WHERE `id` = 'MINI_PL_VEHICLE_RECHARGE_APPLY' AND `del_flag` = 0
|
||||
);
|
||||
|
||||
INSERT INTO `sys_role_menu` (
|
||||
`id`, `role_id`, `menu_id`, `tenant_no`, `order_num`, `remark`,
|
||||
`create_by`, `create_dept_id`, `create_time`, `update_by`, `update_time`, `del_flag`
|
||||
)
|
||||
SELECT
|
||||
MD5(CONCAT(r.id, '|', m.menu_id, '|mini-pl-veh-recharge-apply|v1')),
|
||||
r.id,
|
||||
m.menu_id,
|
||||
IFNULL(NULLIF(r.tenant_no, ''), 'shanxia2.0'),
|
||||
0,
|
||||
'小程序 ETC加油充值申请',
|
||||
'system',
|
||||
'',
|
||||
NOW(),
|
||||
NULL,
|
||||
NOW(),
|
||||
0
|
||||
FROM `sys_role` r
|
||||
JOIN (
|
||||
SELECT '1' AS menu_id UNION ALL
|
||||
SELECT 'MINI_PL_ROOT' UNION ALL
|
||||
SELECT 'MINI_PL_VEHICLE_RECHARGE_APPLY'
|
||||
) m
|
||||
WHERE r.del_flag = 0
|
||||
AND r.role_name IN ('司机', '押运员')
|
||||
AND EXISTS (SELECT 1 FROM `sys_menu` sm WHERE sm.id = m.menu_id AND sm.del_flag = 0)
|
||||
AND NOT EXISTS (
|
||||
SELECT 1 FROM `sys_role_menu` x
|
||||
WHERE x.role_id = r.id AND x.menu_id = m.menu_id AND x.del_flag = 0
|
||||
);
|
||||
@@ -58,6 +58,7 @@ export async function fetchVehicleOptions(q, opts = {}) {
|
||||
const params = {
|
||||
...(q?.trim() ? { q: q.trim() } : {}),
|
||||
...(opts.vehicleType ? { vehicleType: opts.vehicleType } : {}),
|
||||
...(opts.mineVehicles ? { mineVehicles: true } : {}),
|
||||
page: 1,
|
||||
pageSize: 100
|
||||
}
|
||||
|
||||
+47
-1
@@ -20,7 +20,13 @@ function unwrapList(data) {
|
||||
|
||||
function unwrapEntity(data) {
|
||||
if (!data || typeof data !== 'object') return data
|
||||
if (data.data && typeof data.data === 'object' && data.id == null && data.registerNo == null) {
|
||||
if (
|
||||
data.data &&
|
||||
typeof data.data === 'object' &&
|
||||
data.id == null &&
|
||||
data.registerNo == null &&
|
||||
data.applyNo == null
|
||||
) {
|
||||
return data.data
|
||||
}
|
||||
return data
|
||||
@@ -81,6 +87,46 @@ export const sitePlanApi = {
|
||||
db.post(`/transport/site-plan/${planId}/feedback`, payload)
|
||||
}
|
||||
|
||||
export const vehicleRechargeApplyApi = {
|
||||
list: async (params = {}) => {
|
||||
const data = await db.get('/transport/vehicle-recharge-apply/', {
|
||||
mineVehicles: true,
|
||||
...params
|
||||
})
|
||||
return unwrapList(data)
|
||||
},
|
||||
get: async (id) =>
|
||||
unwrapEntity(
|
||||
await db.get(`/transport/vehicle-recharge-apply/${id}`, {
|
||||
mineVehicles: true
|
||||
})
|
||||
),
|
||||
create: async (payload) =>
|
||||
unwrapEntity(
|
||||
await db.post('/transport/vehicle-recharge-apply/', payload, {
|
||||
params: { mineVehicles: true }
|
||||
})
|
||||
),
|
||||
update: async (id, payload) =>
|
||||
unwrapEntity(
|
||||
await db.put(`/transport/vehicle-recharge-apply/${id}`, payload, {
|
||||
params: { mineVehicles: true }
|
||||
})
|
||||
),
|
||||
submit: (id) =>
|
||||
db.post(
|
||||
`/transport/vehicle-recharge-apply/${id}/submit`,
|
||||
{},
|
||||
{ params: { mineVehicles: true } }
|
||||
),
|
||||
cancel: (id) =>
|
||||
db.post(
|
||||
`/transport/vehicle-recharge-apply/${id}/cancel`,
|
||||
{},
|
||||
{ params: { mineVehicles: true } }
|
||||
)
|
||||
}
|
||||
|
||||
export const driverPlanApi = {
|
||||
history: async (params = {}) => {
|
||||
const data = unwrapData(await db.get('/transport/driver-plan/history', params))
|
||||
|
||||
@@ -85,6 +85,8 @@ export const PAGE_PATHS = {
|
||||
bxWfReimburse: '/pages/bx/admin/wf-reimburse',
|
||||
plFuelRegister: '/pages/pl/fuel-register/list',
|
||||
plFuelRegisterForm: '/pages/pl/fuel-register/form',
|
||||
plVehicleRechargeApply: '/pages/pl/vehicle-recharge-apply/list',
|
||||
plVehicleRechargeApplyForm: '/pages/pl/vehicle-recharge-apply/form',
|
||||
plTransportPlan: '/pages/pl/transport-plan/list',
|
||||
plTransportPlanDetail: '/pages/pl/transport-plan/detail',
|
||||
plDriverPlan: '/pages/pl/driver-plan/list',
|
||||
@@ -108,6 +110,7 @@ export const WORKBENCH_ROUTE_MAP = {
|
||||
'bx-wf-advance': PAGE_PATHS.bxWfAdvance,
|
||||
'bx-wf-reimburse': PAGE_PATHS.bxWfReimburse,
|
||||
'pl-fuel-register': PAGE_PATHS.plFuelRegister,
|
||||
'pl-vehicle-recharge-apply': PAGE_PATHS.plVehicleRechargeApply,
|
||||
'pl-transport-plan': PAGE_PATHS.plTransportPlan,
|
||||
'pl-driver-plan': PAGE_PATHS.plDriverPlan,
|
||||
'pl-plan-webview': PAGE_PATHS.mpWebview + '?path=' + encodeURIComponent('/m/pl/plan')
|
||||
|
||||
@@ -56,7 +56,7 @@ export const WORKBENCH_MODULES = [
|
||||
{
|
||||
key: 'pl',
|
||||
title: '运输管理',
|
||||
desc: '加油登记 · 现场运输计划单 · 运输计划 · 司机运输计划单',
|
||||
desc: '加油登记 · ETC充值申请 · 现场运输计划单 · 运输计划 · 司机运输计划单',
|
||||
iconText: '运输',
|
||||
visible: true,
|
||||
menus: [
|
||||
@@ -67,6 +67,13 @@ export const WORKBENCH_MODULES = [
|
||||
icon: '⛽',
|
||||
perms: 'mini:pl:fuelRegister:list'
|
||||
},
|
||||
{
|
||||
name: 'ETC加油充值申请',
|
||||
enabled: true,
|
||||
code: 'pl-vehicle-recharge-apply',
|
||||
icon: '💳',
|
||||
perms: 'mini:pl:vehicleRechargeApply:list'
|
||||
},
|
||||
{
|
||||
name: '现场运输计划单',
|
||||
enabled: true,
|
||||
|
||||
@@ -203,6 +203,14 @@
|
||||
"path": "fuel-register/form",
|
||||
"style": { "navigationStyle": "custom", "navigationBarTitleText": "加油登记" }
|
||||
},
|
||||
{
|
||||
"path": "vehicle-recharge-apply/list",
|
||||
"style": { "navigationStyle": "custom", "navigationBarTitleText": "ETC加油充值申请" }
|
||||
},
|
||||
{
|
||||
"path": "vehicle-recharge-apply/form",
|
||||
"style": { "navigationStyle": "custom", "navigationBarTitleText": "ETC加油充值申请" }
|
||||
},
|
||||
{
|
||||
"path": "transport-plan/list",
|
||||
"style": { "navigationStyle": "custom", "navigationBarTitleText": "现场运输计划单" }
|
||||
|
||||
@@ -0,0 +1,686 @@
|
||||
<template>
|
||||
<view class="bx-page bx-page--form">
|
||||
<view class="topbar" :style="safeAreaStyle">
|
||||
<view class="topbar-left">
|
||||
<text class="topbar-back" @click="goBack">←</text>
|
||||
<text class="topbar-title">{{ pageTitle }}</text>
|
||||
</view>
|
||||
<view class="topbar-right" />
|
||||
</view>
|
||||
|
||||
<view class="page-padded">
|
||||
<view class="form-card">
|
||||
<view class="form-header">
|
||||
<text class="form-header-title">申请信息</text>
|
||||
<text class="form-badge">{{ formBadge }}</text>
|
||||
</view>
|
||||
|
||||
<view v-if="form.applyNo" class="field">
|
||||
<text class="field-label">申请单号</text>
|
||||
<input class="form-input" :value="form.applyNo" disabled />
|
||||
</view>
|
||||
|
||||
<view class="field">
|
||||
<text class="field-label">申请人</text>
|
||||
<input class="form-input" :value="applicantDisplay" disabled />
|
||||
</view>
|
||||
|
||||
<view class="field">
|
||||
<text class="field-label">车牌号<text class="req">*</text></text>
|
||||
<view
|
||||
class="picker-trigger"
|
||||
:class="{ error: fieldErr.licensePlate }"
|
||||
@click="openVehiclePicker"
|
||||
>
|
||||
<text class="value" :class="{ ph: !form.licensePlate }">
|
||||
{{ form.licensePlate || '请选择本人车辆' }}
|
||||
</text>
|
||||
<text class="arrow">›</text>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class="field">
|
||||
<text class="field-label">充值类型<text class="req">*</text></text>
|
||||
<view class="fuel-seg">
|
||||
<view
|
||||
v-for="opt in typeOptions"
|
||||
:key="opt.value"
|
||||
class="fuel-seg__item"
|
||||
:class="{
|
||||
'fuel-seg__item--active': form.rechargeType === opt.value,
|
||||
'fuel-seg__item--disabled': readonly
|
||||
}"
|
||||
@click="onPickType(opt.value)"
|
||||
>
|
||||
{{ opt.label }}
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class="field">
|
||||
<text class="field-label">申请日期<text class="req">*</text></text>
|
||||
<picker
|
||||
mode="date"
|
||||
:value="form.applyDate"
|
||||
:disabled="readonly"
|
||||
@change="onDateChange"
|
||||
>
|
||||
<view class="picker-trigger" :class="{ error: fieldErr.applyDate }">
|
||||
<text class="value" :class="{ ph: !form.applyDate }">
|
||||
{{ form.applyDate || '请选择日期' }}
|
||||
</text>
|
||||
<text class="arrow">›</text>
|
||||
</view>
|
||||
</picker>
|
||||
</view>
|
||||
|
||||
<view class="field">
|
||||
<text class="field-label">期初公里数/KM</text>
|
||||
<input
|
||||
class="form-input"
|
||||
type="digit"
|
||||
:value="form.odometerKm"
|
||||
:disabled="readonly"
|
||||
placeholder="选填"
|
||||
@input="onOdometerInput"
|
||||
/>
|
||||
</view>
|
||||
|
||||
<view class="field">
|
||||
<text class="field-label">备注</text>
|
||||
<textarea
|
||||
class="form-textarea"
|
||||
:value="form.remark"
|
||||
:disabled="readonly"
|
||||
placeholder="选填"
|
||||
:maxlength="500"
|
||||
@input="onRemarkInput"
|
||||
/>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class="form-card">
|
||||
<view class="form-header">
|
||||
<text class="form-header-title">附件</text>
|
||||
</view>
|
||||
<button
|
||||
v-if="!readonly"
|
||||
class="btn btn-primary btn-sm"
|
||||
:disabled="uploading"
|
||||
@click="chooseAttachments"
|
||||
>
|
||||
{{ uploading ? '上传中…' : '上传图片' }}
|
||||
</button>
|
||||
<view v-if="imageUrls.length" class="att-grid">
|
||||
<view v-for="(url, idx) in imageUrls" :key="url + idx" class="att-img" @click="previewAt(idx)">
|
||||
<image :src="resolveUrl(url)" mode="aspectFill" />
|
||||
<view v-if="!readonly" class="del" @click.stop="removeImage(idx)">×</view>
|
||||
</view>
|
||||
</view>
|
||||
<view v-else class="detail-section-empty" style="margin-top: 8px">
|
||||
{{ readonly ? '暂无附件' : '暂无附件(可选,支持相册/拍照)' }}
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view v-if="editId" class="form-card">
|
||||
<view class="form-header">
|
||||
<text class="form-header-title">审批进度</text>
|
||||
</view>
|
||||
<view v-if="!approvalNodes.length" class="detail-section-empty">暂无审批信息</view>
|
||||
<view v-for="(node, idx) in approvalNodes" :key="node.id || idx" class="list-card-kv" style="margin-bottom: 10px">
|
||||
<view class="list-card-kv__row">
|
||||
<text class="list-card-kv__k">节点</text>
|
||||
<text class="list-card-kv__v">{{ node.nodeName || '—' }}</text>
|
||||
</view>
|
||||
<view class="list-card-kv__row">
|
||||
<text class="list-card-kv__k">状态</text>
|
||||
<text class="list-card-kv__v">{{ approvalStatusLabel(node.approvalStatus) }}</text>
|
||||
</view>
|
||||
<view class="list-card-kv__row">
|
||||
<text class="list-card-kv__k">审批人</text>
|
||||
<text class="list-card-kv__v">{{ node.approverName || '—' }}</text>
|
||||
</view>
|
||||
<view v-if="node.approvalOpinion" class="list-card-kv__row">
|
||||
<text class="list-card-kv__k">意见</text>
|
||||
<text class="list-card-kv__v">{{ node.approvalOpinion }}</text>
|
||||
</view>
|
||||
<view v-if="node.approvalTime" class="list-card-kv__row">
|
||||
<text class="list-card-kv__k">时间</text>
|
||||
<text class="list-card-kv__v">{{ formatTime(node.approvalTime) }}</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view v-if="editId" class="form-card">
|
||||
<view class="form-header">
|
||||
<text class="form-header-title">发放信息</text>
|
||||
</view>
|
||||
<view v-if="!record" class="detail-section-empty">暂无</view>
|
||||
<view v-else class="list-card-kv">
|
||||
<view class="list-card-kv__row">
|
||||
<text class="list-card-kv__k">充值订单号</text>
|
||||
<text class="list-card-kv__v">{{ record.rechargeOrderNo || '—' }}</text>
|
||||
</view>
|
||||
<view class="list-card-kv__row">
|
||||
<text class="list-card-kv__k">充值日期</text>
|
||||
<text class="list-card-kv__v">{{ record.rechargeDate || '—' }}</text>
|
||||
</view>
|
||||
<view class="list-card-kv__row">
|
||||
<text class="list-card-kv__k">金额</text>
|
||||
<text class="list-card-kv__v">
|
||||
{{ record.amount != null ? `${Number(record.amount).toFixed(2)} 元` : '—' }}
|
||||
</text>
|
||||
</view>
|
||||
<view class="list-card-kv__row">
|
||||
<text class="list-card-kv__k">卡号</text>
|
||||
<text class="list-card-kv__v">{{ record.cardNo || '—' }}</text>
|
||||
</view>
|
||||
<view class="list-card-kv__row">
|
||||
<text class="list-card-kv__k">加油站/渠道</text>
|
||||
<text class="list-card-kv__v">{{ record.gasStation || '—' }}</text>
|
||||
</view>
|
||||
<view class="list-card-kv__row">
|
||||
<text class="list-card-kv__k">发放人</text>
|
||||
<text class="list-card-kv__v">{{ record.createByName || '—' }}</text>
|
||||
</view>
|
||||
<view v-if="record.remark" class="list-card-kv__row">
|
||||
<text class="list-card-kv__k">备注</text>
|
||||
<text class="list-card-kv__v">{{ record.remark }}</text>
|
||||
</view>
|
||||
</view>
|
||||
<view v-if="recordImageUrls.length" class="att-grid" style="margin-top: 8px">
|
||||
<view
|
||||
v-for="(url, idx) in recordImageUrls"
|
||||
:key="'r' + url + idx"
|
||||
class="att-img"
|
||||
@click="previewRecordAt(idx)"
|
||||
>
|
||||
<image :src="resolveUrl(url)" mode="aspectFill" />
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view v-if="!readonly" class="bottom-action-bar">
|
||||
<button
|
||||
class="btn btn-ghost"
|
||||
style="flex: 1"
|
||||
:disabled="submitting || uploading"
|
||||
@click="onSave"
|
||||
>
|
||||
{{ submitting ? '保存中…' : '保存' }}
|
||||
</button>
|
||||
<button
|
||||
class="btn btn-primary"
|
||||
style="flex: 1"
|
||||
:disabled="submitting || uploading"
|
||||
@click="onSaveAndSubmit"
|
||||
>
|
||||
保存并提交
|
||||
</button>
|
||||
</view>
|
||||
<view v-else-if="canCancel" class="bottom-action-bar">
|
||||
<button class="btn btn-danger btn-block" :disabled="submitting" @click="onCancel">作废</button>
|
||||
</view>
|
||||
|
||||
<view v-if="showVehiclePicker" class="bx-sheet-mask" @click="closeVehiclePicker">
|
||||
<view class="bx-sheet bx-sheet--tall" @click.stop>
|
||||
<view class="bx-sheet__title">选择车牌</view>
|
||||
<view class="bx-sheet__search">
|
||||
<input
|
||||
class="bx-sheet__search-input"
|
||||
:value="vehicleKeyword"
|
||||
placeholder="搜索车牌"
|
||||
confirm-type="search"
|
||||
@input="onVehicleKeywordInput"
|
||||
@confirm="searchVehiclesNow"
|
||||
/>
|
||||
<view
|
||||
v-if="vehicleKeyword.trim()"
|
||||
class="bx-sheet__search-clear"
|
||||
@click="clearVehicleKeyword"
|
||||
>
|
||||
×
|
||||
</view>
|
||||
</view>
|
||||
<scroll-view scroll-y class="bx-sheet__list">
|
||||
<view v-if="vehicleLoading" class="bx-sheet__empty">搜索中…</view>
|
||||
<template v-else>
|
||||
<view v-if="!vehicles.length" class="bx-sheet__empty">
|
||||
{{ vehicleKeyword.trim() ? '无匹配车牌' : '暂无可用车辆' }}
|
||||
</view>
|
||||
<view
|
||||
v-for="item in vehicles"
|
||||
:key="vehicleRowKey(item)"
|
||||
class="bx-sheet__item"
|
||||
:class="{ 'is-selected': vehiclePlate(item) === form.licensePlate }"
|
||||
@click="confirmVehiclePick(item)"
|
||||
>
|
||||
<view>
|
||||
<text>{{ vehiclePlate(item) }}</text>
|
||||
<view v-if="vehicleTypeTag(item)" class="bx-sheet__item-sub">
|
||||
{{ vehicleTypeTag(item) }}
|
||||
</view>
|
||||
</view>
|
||||
<text v-if="vehiclePlate(item) === form.licensePlate">✓</text>
|
||||
</view>
|
||||
</template>
|
||||
</scroll-view>
|
||||
<view class="bx-sheet__footer">
|
||||
<button class="btn btn-ghost btn-block" @click="closeVehiclePicker">取消</button>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref, reactive, computed } from 'vue'
|
||||
import { onLoad } from '@dcloudio/uni-app'
|
||||
import { PAGE_PATHS } from '@/config/api'
|
||||
import { resolveMinioUrl } from '@/config/env'
|
||||
import { vehicleRechargeApplyApi, fetchVehicleOptions } from '@/api/pl'
|
||||
import { chooseAndUploadImages, previewImages } from '@/utils/upload'
|
||||
import { useUserStore } from '@/stores/user'
|
||||
import { getSafeAreaStyle } from '@/utils/safeArea'
|
||||
|
||||
const safeAreaStyle = getSafeAreaStyle()
|
||||
const userStore = useUserStore()
|
||||
|
||||
const MAX_ATTACHMENTS = 5
|
||||
const typeOptions = [
|
||||
{ label: 'ETC', value: 'etc' },
|
||||
{ label: '加油', value: 'fuel' }
|
||||
]
|
||||
|
||||
const editId = ref('')
|
||||
const readonly = ref(false)
|
||||
const submitting = ref(false)
|
||||
const uploading = ref(false)
|
||||
const imageUrls = ref([])
|
||||
const detail = ref(null)
|
||||
const vehicles = ref([])
|
||||
const showVehiclePicker = ref(false)
|
||||
const vehicleKeyword = ref('')
|
||||
const vehicleLoading = ref(false)
|
||||
let vehicleSearchTimer = null
|
||||
let vehicleSearchSeq = 0
|
||||
|
||||
const form = reactive({
|
||||
applyNo: '',
|
||||
applicantId: '',
|
||||
licensePlate: '',
|
||||
rechargeType: 'etc',
|
||||
applyDate: '',
|
||||
odometerKm: '',
|
||||
remark: ''
|
||||
})
|
||||
const fieldErr = reactive({
|
||||
applyDate: false,
|
||||
licensePlate: false
|
||||
})
|
||||
|
||||
const isEdit = computed(() => !!editId.value)
|
||||
const pageTitle = computed(() => {
|
||||
if (readonly.value) return '充值申请详情'
|
||||
return isEdit.value ? '编辑充值申请' : '新增充值申请'
|
||||
})
|
||||
const formBadge = computed(() => {
|
||||
if (readonly.value) return '只读'
|
||||
return isEdit.value ? '编辑' : '新建'
|
||||
})
|
||||
|
||||
const applicantDisplay = computed(() => {
|
||||
if (detail.value?.applicantName) return detail.value.applicantName
|
||||
const info = userStore.userInfo || {}
|
||||
return info.realName || info.nickName || info.username || '当前登录人'
|
||||
})
|
||||
|
||||
const currentUserId = computed(() => {
|
||||
const info = userStore.userInfo || {}
|
||||
return String(info.id || info.userId || '')
|
||||
})
|
||||
|
||||
const isOwn = computed(() => {
|
||||
if (!editId.value) return true
|
||||
return String(detail.value?.applicantId || '') === currentUserId.value
|
||||
})
|
||||
|
||||
const canCancel = computed(
|
||||
() =>
|
||||
isOwn.value &&
|
||||
editId.value &&
|
||||
['draft', 'rejected'].includes(detail.value?.status)
|
||||
)
|
||||
|
||||
const approvalNodes = computed(() => {
|
||||
const d = detail.value
|
||||
if (!d) return []
|
||||
const flow = d.approvalFlow || d.approval_flow || []
|
||||
const history = d.approvalHistory || d.approval_history || []
|
||||
return [...flow, ...history]
|
||||
})
|
||||
|
||||
const record = computed(() => detail.value?.record || null)
|
||||
|
||||
const recordImageUrls = computed(() => {
|
||||
const urls = record.value?.attachmentUrls || record.value?.attachment_urls || ''
|
||||
return String(urls)
|
||||
.split(',')
|
||||
.map((s) => s.trim())
|
||||
.filter(Boolean)
|
||||
})
|
||||
|
||||
function vehiclePlate(v) {
|
||||
return String(v?.licensePlate || v?.license_plate || '').trim()
|
||||
}
|
||||
|
||||
function vehicleTypeTag(v) {
|
||||
const type = v?.vehicleType || v?.vehicle_type
|
||||
if (type === 'self') return '自有'
|
||||
if (type === 'carrier') return '三方'
|
||||
return ''
|
||||
}
|
||||
|
||||
function vehicleRowKey(v) {
|
||||
return String(v?.id || vehiclePlate(v) || '')
|
||||
}
|
||||
|
||||
function todayStr() {
|
||||
const d = new Date()
|
||||
const m = `${d.getMonth() + 1}`.padStart(2, '0')
|
||||
const day = `${d.getDate()}`.padStart(2, '0')
|
||||
return `${d.getFullYear()}-${m}-${day}`
|
||||
}
|
||||
|
||||
function resolveUrl(url) {
|
||||
return resolveMinioUrl(url)
|
||||
}
|
||||
|
||||
function formatTime(v) {
|
||||
if (!v) return '—'
|
||||
return String(v).replace('T', ' ').slice(0, 19)
|
||||
}
|
||||
|
||||
function approvalStatusLabel(v) {
|
||||
const map = {
|
||||
approved: '通过',
|
||||
rejected: '驳回',
|
||||
disbursed: '已发放',
|
||||
pending: '待审批'
|
||||
}
|
||||
return map[v] || v || '—'
|
||||
}
|
||||
|
||||
function goBack() {
|
||||
uni.navigateBack({
|
||||
fail: () => uni.redirectTo({ url: PAGE_PATHS.plVehicleRechargeApply })
|
||||
})
|
||||
}
|
||||
|
||||
function onPickType(value) {
|
||||
if (readonly.value) return
|
||||
form.rechargeType = value
|
||||
}
|
||||
|
||||
function onDateChange(e) {
|
||||
form.applyDate = e.detail.value
|
||||
fieldErr.applyDate = false
|
||||
}
|
||||
|
||||
function onOdometerInput(e) {
|
||||
form.odometerKm = e.detail.value
|
||||
}
|
||||
|
||||
function onRemarkInput(e) {
|
||||
form.remark = e.detail.value
|
||||
}
|
||||
|
||||
async function loadVehicles(keyword = '') {
|
||||
const seq = ++vehicleSearchSeq
|
||||
vehicleLoading.value = true
|
||||
try {
|
||||
const list = await fetchVehicleOptions(keyword, { mineVehicles: true })
|
||||
if (seq !== vehicleSearchSeq) return
|
||||
vehicles.value = Array.isArray(list) ? list : []
|
||||
} catch (e) {
|
||||
if (seq !== vehicleSearchSeq) return
|
||||
vehicles.value = []
|
||||
} finally {
|
||||
if (seq === vehicleSearchSeq) vehicleLoading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
function openVehiclePicker() {
|
||||
if (readonly.value) return
|
||||
showVehiclePicker.value = true
|
||||
vehicleKeyword.value = ''
|
||||
loadVehicles('')
|
||||
}
|
||||
|
||||
function closeVehiclePicker() {
|
||||
showVehiclePicker.value = false
|
||||
if (vehicleSearchTimer) {
|
||||
clearTimeout(vehicleSearchTimer)
|
||||
vehicleSearchTimer = null
|
||||
}
|
||||
}
|
||||
|
||||
function onVehicleKeywordInput(e) {
|
||||
vehicleKeyword.value = e.detail.value || ''
|
||||
if (vehicleSearchTimer) clearTimeout(vehicleSearchTimer)
|
||||
vehicleSearchTimer = setTimeout(() => {
|
||||
loadVehicles(vehicleKeyword.value)
|
||||
}, 300)
|
||||
}
|
||||
|
||||
function searchVehiclesNow() {
|
||||
if (vehicleSearchTimer) {
|
||||
clearTimeout(vehicleSearchTimer)
|
||||
vehicleSearchTimer = null
|
||||
}
|
||||
loadVehicles(vehicleKeyword.value)
|
||||
}
|
||||
|
||||
function clearVehicleKeyword() {
|
||||
vehicleKeyword.value = ''
|
||||
if (vehicleSearchTimer) {
|
||||
clearTimeout(vehicleSearchTimer)
|
||||
vehicleSearchTimer = null
|
||||
}
|
||||
loadVehicles('')
|
||||
}
|
||||
|
||||
function confirmVehiclePick(item) {
|
||||
const plate = vehiclePlate(item)
|
||||
if (!plate) return
|
||||
form.licensePlate = plate
|
||||
fieldErr.licensePlate = false
|
||||
closeVehiclePicker()
|
||||
}
|
||||
|
||||
async function chooseAttachments() {
|
||||
uploading.value = true
|
||||
try {
|
||||
const urls = await chooseAndUploadImages({
|
||||
folder: 'pl/vehicle-recharge/apply',
|
||||
maxCount: MAX_ATTACHMENTS,
|
||||
currentUrls: imageUrls.value
|
||||
})
|
||||
if (urls.length) imageUrls.value = urls
|
||||
} finally {
|
||||
uploading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
function removeImage(idx) {
|
||||
imageUrls.value = imageUrls.value.filter((_, i) => i !== idx)
|
||||
}
|
||||
|
||||
function previewAt(idx) {
|
||||
previewImages(
|
||||
imageUrls.value.map((u) => resolveUrl(u)),
|
||||
idx
|
||||
)
|
||||
}
|
||||
|
||||
function previewRecordAt(idx) {
|
||||
previewImages(
|
||||
recordImageUrls.value.map((u) => resolveUrl(u)),
|
||||
idx
|
||||
)
|
||||
}
|
||||
|
||||
function validate() {
|
||||
fieldErr.applyDate = !form.applyDate
|
||||
fieldErr.licensePlate = !form.licensePlate
|
||||
if (fieldErr.applyDate || fieldErr.licensePlate) {
|
||||
uni.showToast({ title: '请完善必填项', icon: 'none' })
|
||||
return false
|
||||
}
|
||||
if (!form.rechargeType) {
|
||||
uni.showToast({ title: '请选择充值类型', icon: 'none' })
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
function buildPayload() {
|
||||
const odo = form.odometerKm === '' || form.odometerKm == null ? null : Number(form.odometerKm)
|
||||
return {
|
||||
licensePlate: form.licensePlate,
|
||||
rechargeType: form.rechargeType,
|
||||
applyDate: form.applyDate,
|
||||
odometerKm: Number.isNaN(odo) ? null : odo,
|
||||
attachmentUrls: imageUrls.value.join(',') || null,
|
||||
remark: form.remark || null,
|
||||
applicantId: currentUserId.value || null
|
||||
}
|
||||
}
|
||||
|
||||
function fillFromDetail(data) {
|
||||
detail.value = data
|
||||
form.applyNo = data.applyNo || ''
|
||||
form.applicantId = data.applicantId || ''
|
||||
form.licensePlate = data.licensePlate || ''
|
||||
form.rechargeType = data.rechargeType || 'etc'
|
||||
form.applyDate = data.applyDate || ''
|
||||
form.odometerKm =
|
||||
data.odometerKm != null && data.odometerKm !== '' ? String(data.odometerKm) : ''
|
||||
form.remark = data.remark || ''
|
||||
imageUrls.value = String(data.attachmentUrls || '')
|
||||
.split(',')
|
||||
.map((s) => s.trim())
|
||||
.filter(Boolean)
|
||||
const own = String(data.applicantId || '') === currentUserId.value
|
||||
const editable = ['draft', 'rejected'].includes(data.status)
|
||||
readonly.value = !(own && editable)
|
||||
}
|
||||
|
||||
async function onSave() {
|
||||
if (!validate() || submitting.value) return
|
||||
submitting.value = true
|
||||
try {
|
||||
const payload = buildPayload()
|
||||
let saved
|
||||
if (editId.value) {
|
||||
saved = await vehicleRechargeApplyApi.update(editId.value, payload)
|
||||
} else {
|
||||
saved = await vehicleRechargeApplyApi.create(payload)
|
||||
editId.value = saved.id
|
||||
}
|
||||
fillFromDetail(saved)
|
||||
uni.showToast({ title: '已保存', icon: 'success' })
|
||||
} catch (e) {
|
||||
// toasted
|
||||
} finally {
|
||||
submitting.value = false
|
||||
}
|
||||
}
|
||||
|
||||
async function onSaveAndSubmit() {
|
||||
if (!validate() || submitting.value) return
|
||||
submitting.value = true
|
||||
try {
|
||||
const payload = buildPayload()
|
||||
let saved
|
||||
if (editId.value) {
|
||||
saved = await vehicleRechargeApplyApi.update(editId.value, payload)
|
||||
} else {
|
||||
saved = await vehicleRechargeApplyApi.create(payload)
|
||||
editId.value = saved.id
|
||||
}
|
||||
await vehicleRechargeApplyApi.submit(editId.value)
|
||||
const latest = await vehicleRechargeApplyApi.get(editId.value)
|
||||
fillFromDetail(latest)
|
||||
uni.showToast({ title: '已提交', icon: 'success' })
|
||||
} catch (e) {
|
||||
// toasted
|
||||
} finally {
|
||||
submitting.value = false
|
||||
}
|
||||
}
|
||||
|
||||
function onCancel() {
|
||||
uni.showModal({
|
||||
title: '作废确认',
|
||||
content: '确定作废该充值申请吗?',
|
||||
confirmText: '作废',
|
||||
confirmColor: '#ef4444',
|
||||
success: async (res) => {
|
||||
if (!res.confirm) return
|
||||
submitting.value = true
|
||||
try {
|
||||
await vehicleRechargeApplyApi.cancel(editId.value)
|
||||
uni.showToast({ title: '已作废', icon: 'success' })
|
||||
setTimeout(goBack, 500)
|
||||
} catch (e) {
|
||||
// toasted
|
||||
} finally {
|
||||
submitting.value = false
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
async function initNew() {
|
||||
const info = userStore.userInfo || {}
|
||||
form.applicantId = String(info.id || info.userId || '')
|
||||
form.applyDate = todayStr()
|
||||
form.rechargeType = 'etc'
|
||||
readonly.value = false
|
||||
await loadVehicles('')
|
||||
if (vehicles.value.length === 1) {
|
||||
form.licensePlate = vehiclePlate(vehicles.value[0])
|
||||
} else if (!vehicles.value.length) {
|
||||
uni.showToast({
|
||||
title: '暂无可用车辆,请联系管理员绑定',
|
||||
icon: 'none',
|
||||
duration: 2500
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
async function loadDetail(id) {
|
||||
const data = await vehicleRechargeApplyApi.get(id)
|
||||
fillFromDetail(data)
|
||||
}
|
||||
|
||||
onLoad(async (query) => {
|
||||
const id = query?.id || ''
|
||||
if (id) {
|
||||
editId.value = id
|
||||
try {
|
||||
await loadDetail(id)
|
||||
} catch (e) {
|
||||
uni.showToast({ title: '加载失败', icon: 'none' })
|
||||
}
|
||||
} else {
|
||||
await initNew()
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
@import '@/styles/bx-theme.scss';
|
||||
</style>
|
||||
@@ -0,0 +1,307 @@
|
||||
<template>
|
||||
<view class="bx-page">
|
||||
<view class="topbar" :style="safeAreaStyle">
|
||||
<view class="topbar-left">
|
||||
<text class="topbar-back" @click="goBack">←</text>
|
||||
<text class="topbar-title">ETC加油充值申请</text>
|
||||
</view>
|
||||
<view class="topbar-right" />
|
||||
</view>
|
||||
|
||||
<view class="fab-add" @click="goForm()">
|
||||
<view class="fab-add__bar fab-add__bar--h" />
|
||||
<view class="fab-add__bar fab-add__bar--v" />
|
||||
</view>
|
||||
|
||||
<view class="search-wrap">
|
||||
<view class="search-box">
|
||||
<input
|
||||
class="search-input"
|
||||
v-model="keyword"
|
||||
placeholder="搜索申请单号/车牌"
|
||||
confirm-type="search"
|
||||
@confirm="onRefresh"
|
||||
/>
|
||||
<view v-if="keyword.trim()" class="search-box__clear" @click="clearKeyword">×</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class="search-wrap" style="padding-top: 0">
|
||||
<scroll-view scroll-x class="search-filter-scroll" :show-scrollbar="false">
|
||||
<view class="search-filter">
|
||||
<view
|
||||
v-for="tab in tabs"
|
||||
:key="tab.value === '' ? '__all' : tab.value"
|
||||
class="filter-tag"
|
||||
:class="{ active: activeTab === tab.value }"
|
||||
@click="onTabChange(tab.value)"
|
||||
>
|
||||
{{ tab.label }}
|
||||
</view>
|
||||
</view>
|
||||
</scroll-view>
|
||||
</view>
|
||||
|
||||
<scroll-view
|
||||
class="page-padded list-scroll"
|
||||
scroll-y
|
||||
:style="{ height: listHeight }"
|
||||
refresher-enabled
|
||||
:refresher-triggered="refreshing"
|
||||
@refresherrefresh="onPullRefresh"
|
||||
@scrolltolower="onLoadMore"
|
||||
>
|
||||
<view v-if="!list.length && !loading" class="empty-state empty-state--fill">
|
||||
<text>暂无充值申请</text>
|
||||
</view>
|
||||
|
||||
<view
|
||||
v-for="item in list"
|
||||
:key="item.id"
|
||||
class="expense-card"
|
||||
@click="goForm(item.id)"
|
||||
>
|
||||
<view class="ec-top">
|
||||
<view class="ec-type">
|
||||
<text class="advance-list-card__title">{{ item.licensePlate || '—' }}</text>
|
||||
</view>
|
||||
<text class="status-tag" :class="statusTagClass(item.status)">
|
||||
{{ statusLabel(item.status) }}
|
||||
</text>
|
||||
</view>
|
||||
<view class="ec-amount-label">充值类型</view>
|
||||
<view class="ec-amount">{{ typeLabel(item.rechargeType) }}</view>
|
||||
<view class="list-card-kv">
|
||||
<view class="list-card-kv__row">
|
||||
<text class="list-card-kv__k">申请单号</text>
|
||||
<text class="list-card-kv__v">{{ item.applyNo || '—' }}</text>
|
||||
</view>
|
||||
<view class="list-card-kv__row">
|
||||
<text class="list-card-kv__k">申请日期</text>
|
||||
<text class="list-card-kv__v">{{ item.applyDate || '—' }}</text>
|
||||
</view>
|
||||
<view class="list-card-kv__row">
|
||||
<text class="list-card-kv__k">申请人</text>
|
||||
<text class="list-card-kv__v">{{ item.applicantName || '—' }}</text>
|
||||
</view>
|
||||
<view class="list-card-kv__row">
|
||||
<text class="list-card-kv__k">期初公里数</text>
|
||||
<text class="list-card-kv__v">{{ item.odometerKm != null ? item.odometerKm : '—' }}</text>
|
||||
</view>
|
||||
<view v-if="item.remark" class="list-card-kv__row">
|
||||
<text class="list-card-kv__k">备注</text>
|
||||
<text class="list-card-kv__v">{{ item.remark }}</text>
|
||||
</view>
|
||||
</view>
|
||||
<view class="ec-bottom" @click.stop>
|
||||
<view class="op-actions">
|
||||
<template v-if="canWrite(item)">
|
||||
<button class="btn btn-sm btn-ghost" @click="handleSubmit(item)">提交</button>
|
||||
<button class="btn btn-sm btn-primary" @click="goForm(item.id)">编辑</button>
|
||||
<button class="btn btn-sm btn-danger" @click="handleCancel(item)">作废</button>
|
||||
</template>
|
||||
<button v-else class="btn btn-sm btn-primary" @click="goForm(item.id)">查看</button>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view v-if="list.length" class="list-footer-tip">
|
||||
{{ finished ? '没有更多了' : loading ? '加载中...' : '上拉加载更多' }}
|
||||
</view>
|
||||
</scroll-view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref } from 'vue'
|
||||
import { onShow } from '@dcloudio/uni-app'
|
||||
import { PAGE_PATHS } from '@/config/api'
|
||||
import { vehicleRechargeApplyApi } from '@/api/pl'
|
||||
import { useUserStore } from '@/stores/user'
|
||||
import { getSafeAreaStyle } from '@/utils/safeArea'
|
||||
|
||||
const safeAreaStyle = getSafeAreaStyle()
|
||||
const userStore = useUserStore()
|
||||
|
||||
const tabs = [
|
||||
{ label: '全部', value: '' },
|
||||
{ label: '草稿', value: 'draft' },
|
||||
{ label: '审批中', value: 'in_approval' },
|
||||
{ label: '已驳回', value: 'rejected' },
|
||||
{ label: '已发放', value: 'disbursed' },
|
||||
{ label: '已作废', value: 'cancelled' }
|
||||
]
|
||||
|
||||
const keyword = ref('')
|
||||
const activeTab = ref('')
|
||||
const list = ref([])
|
||||
const loading = ref(false)
|
||||
const finished = ref(false)
|
||||
const refreshing = ref(false)
|
||||
const currentPage = ref(1)
|
||||
const pageSize = 10
|
||||
const listHeight = ref('60vh')
|
||||
|
||||
function currentUserId() {
|
||||
const info = userStore.userInfo || {}
|
||||
return String(info.id || info.userId || '')
|
||||
}
|
||||
|
||||
function canWrite(item) {
|
||||
if (!item) return false
|
||||
if (!['draft', 'rejected'].includes(item.status)) return false
|
||||
return String(item.applicantId || '') === currentUserId()
|
||||
}
|
||||
|
||||
function typeLabel(v) {
|
||||
if (v === 'etc') return 'ETC'
|
||||
if (v === 'fuel') return '加油'
|
||||
return v || '—'
|
||||
}
|
||||
|
||||
function statusLabel(v) {
|
||||
const map = {
|
||||
draft: '草稿',
|
||||
in_approval: '审批中',
|
||||
rejected: '已驳回',
|
||||
disbursed: '已发放',
|
||||
cancelled: '已作废',
|
||||
pending: '待发放'
|
||||
}
|
||||
return map[v] || v || '—'
|
||||
}
|
||||
|
||||
function statusTagClass(v) {
|
||||
if (v === 'draft') return 's-draft'
|
||||
if (v === 'in_approval' || v === 'pending') return 's-pending'
|
||||
if (v === 'rejected') return 's-rejected'
|
||||
if (v === 'disbursed') return 's-approved'
|
||||
if (v === 'cancelled') return 's-withdrawn'
|
||||
return 's-draft'
|
||||
}
|
||||
|
||||
function computeListHeight() {
|
||||
try {
|
||||
const sys = uni.getSystemInfoSync()
|
||||
const h = (sys.windowHeight || 600) - 210
|
||||
listHeight.value = `${Math.max(h, 320)}px`
|
||||
} catch (e) {
|
||||
listHeight.value = '60vh'
|
||||
}
|
||||
}
|
||||
|
||||
async function fetchPage() {
|
||||
if (loading.value && !refreshing.value) return
|
||||
loading.value = true
|
||||
try {
|
||||
const params = {
|
||||
page: currentPage.value,
|
||||
pageSize
|
||||
}
|
||||
if (activeTab.value) params.status = activeTab.value
|
||||
if (keyword.value.trim()) params.q = keyword.value.trim()
|
||||
const { items, total } = await vehicleRechargeApplyApi.list(params)
|
||||
if (currentPage.value === 1) {
|
||||
list.value = items
|
||||
} else {
|
||||
list.value = list.value.concat(items)
|
||||
}
|
||||
currentPage.value += 1
|
||||
finished.value = items.length < pageSize || list.value.length >= total
|
||||
} catch (e) {
|
||||
finished.value = true
|
||||
} finally {
|
||||
loading.value = false
|
||||
refreshing.value = false
|
||||
}
|
||||
}
|
||||
|
||||
function onRefresh() {
|
||||
currentPage.value = 1
|
||||
finished.value = false
|
||||
loading.value = false
|
||||
list.value = []
|
||||
fetchPage()
|
||||
}
|
||||
|
||||
function onPullRefresh() {
|
||||
refreshing.value = true
|
||||
currentPage.value = 1
|
||||
finished.value = false
|
||||
fetchPage()
|
||||
}
|
||||
|
||||
function onLoadMore() {
|
||||
if (finished.value || loading.value) return
|
||||
fetchPage()
|
||||
}
|
||||
|
||||
function onTabChange(value) {
|
||||
activeTab.value = value
|
||||
onRefresh()
|
||||
}
|
||||
|
||||
function clearKeyword() {
|
||||
keyword.value = ''
|
||||
onRefresh()
|
||||
}
|
||||
|
||||
function goBack() {
|
||||
uni.navigateBack({ fail: () => uni.reLaunch({ url: PAGE_PATHS.workbench }) })
|
||||
}
|
||||
|
||||
function goForm(id) {
|
||||
const q = id ? `?id=${id}` : ''
|
||||
uni.navigateTo({ url: `${PAGE_PATHS.plVehicleRechargeApplyForm}${q}` })
|
||||
}
|
||||
|
||||
function handleSubmit(item) {
|
||||
uni.showModal({
|
||||
title: '提交确认',
|
||||
content: '确定提交该充值申请进入审批吗?',
|
||||
confirmText: '提交',
|
||||
success: async (res) => {
|
||||
if (!res.confirm) return
|
||||
try {
|
||||
await vehicleRechargeApplyApi.submit(item.id)
|
||||
uni.showToast({ title: '已提交', icon: 'success' })
|
||||
onRefresh()
|
||||
} catch (e) {
|
||||
// toasted
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
function handleCancel(item) {
|
||||
uni.showModal({
|
||||
title: '作废确认',
|
||||
content: '确定作废该充值申请吗?',
|
||||
confirmText: '作废',
|
||||
confirmColor: '#ef4444',
|
||||
success: async (res) => {
|
||||
if (!res.confirm) return
|
||||
try {
|
||||
await vehicleRechargeApplyApi.cancel(item.id)
|
||||
uni.showToast({ title: '已作废', icon: 'success' })
|
||||
onRefresh()
|
||||
} catch (e) {
|
||||
// toasted
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
onShow(() => {
|
||||
computeListHeight()
|
||||
onRefresh()
|
||||
})
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
@import '@/styles/bx-theme.scss';
|
||||
|
||||
.list-scroll {
|
||||
box-sizing: border-box;
|
||||
}
|
||||
</style>
|
||||
Reference in new issue
Block a user