diff --git a/docs/sql/migrations/2026-09-27-mini-pl-vehicle-recharge-apply-menus.sql b/docs/sql/migrations/2026-09-27-mini-pl-vehicle-recharge-apply-menus.sql
new file mode 100644
index 000000000..34561cdc7
--- /dev/null
+++ b/docs/sql/migrations/2026-09-27-mini-pl-vehicle-recharge-apply-menus.sql
@@ -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
+ );
diff --git a/miniprogram/api/dbOptions.js b/miniprogram/api/dbOptions.js
index 9f92c75b3..cd0898e4f 100644
--- a/miniprogram/api/dbOptions.js
+++ b/miniprogram/api/dbOptions.js
@@ -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
}
diff --git a/miniprogram/api/pl.js b/miniprogram/api/pl.js
index e561ed78b..45de718b3 100644
--- a/miniprogram/api/pl.js
+++ b/miniprogram/api/pl.js
@@ -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))
diff --git a/miniprogram/config/api.js b/miniprogram/config/api.js
index e64137a64..6d9e645d4 100644
--- a/miniprogram/config/api.js
+++ b/miniprogram/config/api.js
@@ -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')
diff --git a/miniprogram/config/workbench-menus.js b/miniprogram/config/workbench-menus.js
index 474ac77a0..4b72a8cc3 100644
--- a/miniprogram/config/workbench-menus.js
+++ b/miniprogram/config/workbench-menus.js
@@ -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,
diff --git a/miniprogram/pages.json b/miniprogram/pages.json
index 968105c90..448a43929 100644
--- a/miniprogram/pages.json
+++ b/miniprogram/pages.json
@@ -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": "现场运输计划单" }
diff --git a/miniprogram/pages/pl/vehicle-recharge-apply/form.vue b/miniprogram/pages/pl/vehicle-recharge-apply/form.vue
new file mode 100644
index 000000000..5810f6285
--- /dev/null
+++ b/miniprogram/pages/pl/vehicle-recharge-apply/form.vue
@@ -0,0 +1,686 @@
+
+
+
+
+ ←
+ {{ pageTitle }}
+
+
+
+
+
+
+
+
+
+ 申请单号
+
+
+
+
+ 申请人
+
+
+
+
+ 车牌号*
+
+
+ {{ form.licensePlate || '请选择本人车辆' }}
+
+ ›
+
+
+
+
+ 充值类型*
+
+
+ {{ opt.label }}
+
+
+
+
+
+ 申请日期*
+
+
+
+ {{ form.applyDate || '请选择日期' }}
+
+ ›
+
+
+
+
+
+ 期初公里数/KM
+
+
+
+
+ 备注
+
+
+
+
+
+
+
+
+
+
+ ×
+
+
+
+ {{ readonly ? '暂无附件' : '暂无附件(可选,支持相册/拍照)' }}
+
+
+
+
+
+ 暂无审批信息
+
+
+ 节点
+ {{ node.nodeName || '—' }}
+
+
+ 状态
+ {{ approvalStatusLabel(node.approvalStatus) }}
+
+
+ 审批人
+ {{ node.approverName || '—' }}
+
+
+ 意见
+ {{ node.approvalOpinion }}
+
+
+ 时间
+ {{ formatTime(node.approvalTime) }}
+
+
+
+
+
+
+ 暂无
+
+
+ 充值订单号
+ {{ record.rechargeOrderNo || '—' }}
+
+
+ 充值日期
+ {{ record.rechargeDate || '—' }}
+
+
+ 金额
+
+ {{ record.amount != null ? `${Number(record.amount).toFixed(2)} 元` : '—' }}
+
+
+
+ 卡号
+ {{ record.cardNo || '—' }}
+
+
+ 加油站/渠道
+ {{ record.gasStation || '—' }}
+
+
+ 发放人
+ {{ record.createByName || '—' }}
+
+
+ 备注
+ {{ record.remark }}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 选择车牌
+
+
+
+ ×
+
+
+
+ 搜索中…
+
+
+ {{ vehicleKeyword.trim() ? '无匹配车牌' : '暂无可用车辆' }}
+
+
+
+ {{ vehiclePlate(item) }}
+
+ {{ vehicleTypeTag(item) }}
+
+
+ ✓
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/miniprogram/pages/pl/vehicle-recharge-apply/list.vue b/miniprogram/pages/pl/vehicle-recharge-apply/list.vue
new file mode 100644
index 000000000..f40f11b9b
--- /dev/null
+++ b/miniprogram/pages/pl/vehicle-recharge-apply/list.vue
@@ -0,0 +1,307 @@
+
+
+
+
+ ←
+ ETC加油充值申请
+
+
+
+
+
+
+
+
+
+
+
+
+ ×
+
+
+
+
+
+
+
+ {{ tab.label }}
+
+
+
+
+
+
+
+ 暂无充值申请
+
+
+
+
+
+ {{ item.licensePlate || '—' }}
+
+
+ {{ statusLabel(item.status) }}
+
+
+ 充值类型
+ {{ typeLabel(item.rechargeType) }}
+
+
+ 申请单号
+ {{ item.applyNo || '—' }}
+
+
+ 申请日期
+ {{ item.applyDate || '—' }}
+
+
+ 申请人
+ {{ item.applicantName || '—' }}
+
+
+ 期初公里数
+ {{ item.odometerKm != null ? item.odometerKm : '—' }}
+
+
+ 备注
+ {{ item.remark }}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+