f
This commit is contained in:
1
.env
1
.env
@@ -15,3 +15,4 @@ VITE_API_BASE_URL=https://www.quannengcha.com/api/v1
|
|||||||
|
|
||||||
# 想用本地接口时注释掉上面那行,取消下面这行注释:
|
# 想用本地接口时注释掉上面那行,取消下面这行注释:
|
||||||
# VITE_API_BASE_URL=http://127.0.0.1:8888/api/v1
|
# VITE_API_BASE_URL=http://127.0.0.1:8888/api/v1
|
||||||
|
|
||||||
|
|||||||
@@ -1,2 +1,4 @@
|
|||||||
# 生产构建:指向 qnc-server-v3 线上网关
|
# 生产构建:指向 qnc-server-v3 线上网关
|
||||||
VITE_API_BASE_URL=https://www.quannengcha.com/api/v1
|
VITE_API_BASE_URL=https://www.quannengcha.com/api/v1
|
||||||
|
# qnc-webview-v3 H5 站点(小程序 web-view / 分享链接)
|
||||||
|
VITE_H5_ORIGIN=https://www.quannengcha.com
|
||||||
|
|||||||
1
components.d.ts
vendored
1
components.d.ts
vendored
@@ -10,6 +10,7 @@ declare module 'vue' {
|
|||||||
AppFooter: typeof import('./src/components/AppFooter.vue')['default']
|
AppFooter: typeof import('./src/components/AppFooter.vue')['default']
|
||||||
AppLogos: typeof import('./src/components/AppLogos.vue')['default']
|
AppLogos: typeof import('./src/components/AppLogos.vue')['default']
|
||||||
InputEntry: typeof import('./src/components/InputEntry.vue')['default']
|
InputEntry: typeof import('./src/components/InputEntry.vue')['default']
|
||||||
|
ReportShareBar: typeof import('./src/components/report/ReportShareBar.vue')['default']
|
||||||
VehicleBlockFallback: typeof import('./src/components/report/VehicleBlockFallback.vue')['default']
|
VehicleBlockFallback: typeof import('./src/components/report/VehicleBlockFallback.vue')['default']
|
||||||
VehicleBlockQCXG1H7Y: typeof import('./src/components/report/blocks/VehicleBlockQCXG1H7Y.vue')['default']
|
VehicleBlockQCXG1H7Y: typeof import('./src/components/report/blocks/VehicleBlockQCXG1H7Y.vue')['default']
|
||||||
VehicleBlockQCXG1U4U: typeof import('./src/components/report/blocks/VehicleBlockQCXG1U4U.vue')['default']
|
VehicleBlockQCXG1U4U: typeof import('./src/components/report/blocks/VehicleBlockQCXG1U4U.vue')['default']
|
||||||
|
|||||||
2
env.d.ts
vendored
2
env.d.ts
vendored
@@ -5,6 +5,8 @@ interface ImportMetaEnv {
|
|||||||
readonly VITE_API_BASE_URL?: string
|
readonly VITE_API_BASE_URL?: string
|
||||||
/** H5 开发代理目标,仅 vite 使用,默认 http://127.0.0.1:8888 */
|
/** H5 开发代理目标,仅 vite 使用,默认 http://127.0.0.1:8888 */
|
||||||
readonly VITE_API_PROXY_TARGET?: string
|
readonly VITE_API_PROXY_TARGET?: string
|
||||||
|
/** qnc-webview-v3 站点根地址,如 https://www.quannengcha.com */
|
||||||
|
readonly VITE_H5_ORIGIN?: string
|
||||||
}
|
}
|
||||||
|
|
||||||
interface ImportMeta {
|
interface ImportMeta {
|
||||||
|
|||||||
@@ -29,6 +29,16 @@ export async function getQueryList(params = {}, requestConfig) {
|
|||||||
return res.data
|
return res.data
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** 生成报告分享链接(与 H5 ShareReportButton POST /query/generate_share_link 一致) */
|
||||||
|
export async function generateQueryShareLink(body, requestConfig = {}) {
|
||||||
|
const res = await http.post('/query/generate_share_link', body, {
|
||||||
|
skipLoading: true,
|
||||||
|
skipBizToast: true,
|
||||||
|
...requestConfig,
|
||||||
|
})
|
||||||
|
return res.data
|
||||||
|
}
|
||||||
|
|
||||||
/** 创建查询临时单(与 H5 `InquireForm` 一致:POST /api/v1/query/service/:product) */
|
/** 创建查询临时单(与 H5 `InquireForm` 一致:POST /api/v1/query/service/:product) */
|
||||||
export async function postQueryService(productEn, body, requestConfig) {
|
export async function postQueryService(productEn, body, requestConfig) {
|
||||||
const enc = encodeURIComponent(productEn)
|
const enc = encodeURIComponent(productEn)
|
||||||
|
|||||||
107
src/components/report/ReportShareBar.vue
Normal file
107
src/components/report/ReportShareBar.vue
Normal file
@@ -0,0 +1,107 @@
|
|||||||
|
<script setup>
|
||||||
|
import { ref } from 'vue'
|
||||||
|
import { fetchReportShareUrl } from '@/utils/reportH5Link'
|
||||||
|
|
||||||
|
const props = defineProps({
|
||||||
|
orderId: { type: String, default: '' },
|
||||||
|
orderNo: { type: String, default: '' },
|
||||||
|
})
|
||||||
|
|
||||||
|
const loading = ref(false)
|
||||||
|
|
||||||
|
async function copyLink() {
|
||||||
|
if (loading.value)
|
||||||
|
return
|
||||||
|
if (!props.orderId && !props.orderNo) {
|
||||||
|
uni.showToast({ title: '缺少订单信息', icon: 'none' })
|
||||||
|
return
|
||||||
|
}
|
||||||
|
loading.value = true
|
||||||
|
uni.showLoading({ title: '生成链接…', mask: true })
|
||||||
|
try {
|
||||||
|
const url = await fetchReportShareUrl({
|
||||||
|
orderId: props.orderId,
|
||||||
|
orderNo: props.orderNo,
|
||||||
|
})
|
||||||
|
uni.hideLoading()
|
||||||
|
await new Promise((resolve, reject) => {
|
||||||
|
uni.setClipboardData({
|
||||||
|
data: url,
|
||||||
|
success: resolve,
|
||||||
|
fail: reject,
|
||||||
|
})
|
||||||
|
})
|
||||||
|
uni.showToast({ title: '链接已复制,可在浏览器打开', icon: 'none', duration: 2500 })
|
||||||
|
}
|
||||||
|
catch (e) {
|
||||||
|
uni.hideLoading()
|
||||||
|
uni.showToast({
|
||||||
|
title: e?.message || '复制失败',
|
||||||
|
icon: 'none',
|
||||||
|
duration: 2500,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
finally {
|
||||||
|
loading.value = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<view class="share-bar">
|
||||||
|
<view class="share-bar-inner">
|
||||||
|
<button
|
||||||
|
class="share-btn"
|
||||||
|
:loading="loading"
|
||||||
|
:disabled="loading"
|
||||||
|
@tap="copyLink"
|
||||||
|
>
|
||||||
|
<view class="share-btn-icon i-carbon-copy" />
|
||||||
|
<text>{{ loading ? '生成中…' : '复制链接' }}</text>
|
||||||
|
</button>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style scoped lang="scss">
|
||||||
|
.share-bar {
|
||||||
|
position: fixed;
|
||||||
|
left: 0;
|
||||||
|
right: 0;
|
||||||
|
bottom: 0;
|
||||||
|
z-index: 100;
|
||||||
|
background: #fff;
|
||||||
|
border-top: 1rpx solid #e5e6eb;
|
||||||
|
box-shadow: 0 -4rpx 24rpx rgba(0, 0, 0, 0.06);
|
||||||
|
}
|
||||||
|
|
||||||
|
.share-bar-inner {
|
||||||
|
padding: 20rpx 24rpx calc(20rpx + env(safe-area-inset-bottom));
|
||||||
|
box-sizing: border-box;
|
||||||
|
}
|
||||||
|
|
||||||
|
.share-btn {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
gap: 12rpx;
|
||||||
|
width: 100%;
|
||||||
|
margin: 0;
|
||||||
|
height: 88rpx;
|
||||||
|
line-height: 88rpx;
|
||||||
|
font-size: 30rpx;
|
||||||
|
font-weight: 600;
|
||||||
|
color: #fff;
|
||||||
|
background: linear-gradient(90deg, #1768ff 0%, #4d94ff 100%);
|
||||||
|
border-radius: 44rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.share-btn::after {
|
||||||
|
border: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.share-btn-icon {
|
||||||
|
font-size: 36rpx;
|
||||||
|
color: #fff;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
<script setup>
|
<script setup>
|
||||||
import { computed } from 'vue'
|
import { computed } from 'vue'
|
||||||
|
|
||||||
/** 人车核验简版(与 H5 CQCXGGB2Q:verify_code) */
|
/** 人车核验简版(与 H5 CQCXGGB2Q:verify_code 1 一致 / 0 不一致) */
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
blockTitle: { type: String, default: '' },
|
blockTitle: { type: String, default: '' },
|
||||||
apiId: { type: String, default: '' },
|
apiId: { type: String, default: '' },
|
||||||
@@ -23,7 +23,7 @@ const isMatch = computed(() => {
|
|||||||
const n = Number(code)
|
const n = Number(code)
|
||||||
if (n === 1)
|
if (n === 1)
|
||||||
return true
|
return true
|
||||||
if (n === 2)
|
if (n === 0)
|
||||||
return false
|
return false
|
||||||
return null
|
return null
|
||||||
})
|
})
|
||||||
@@ -32,7 +32,7 @@ const resultText = computed(() => {
|
|||||||
if (isMatch.value === true)
|
if (isMatch.value === true)
|
||||||
return '一致'
|
return '一致'
|
||||||
if (isMatch.value === false)
|
if (isMatch.value === false)
|
||||||
return '不匹配'
|
return '不一致'
|
||||||
return '暂无结果'
|
return '暂无结果'
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|||||||
17
src/config/h5.js
Normal file
17
src/config/h5.js
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
/**
|
||||||
|
* qnc-webview-v3 H5 站点根地址(不含 /api/v1)
|
||||||
|
* 小程序内 web-view 打开报告页、分享链接拼接用。
|
||||||
|
*/
|
||||||
|
export function getH5Origin() {
|
||||||
|
const fromEnv = import.meta.env.VITE_H5_ORIGIN?.trim()
|
||||||
|
if (fromEnv)
|
||||||
|
return fromEnv.replace(/\/$/, '')
|
||||||
|
|
||||||
|
const apiBase = import.meta.env.VITE_API_BASE_URL?.trim() || ''
|
||||||
|
if (/quannengcha\.com/i.test(apiBase))
|
||||||
|
return apiBase.replace(/\/api\/v1\/?$/i, '').replace(/\/$/, '') || 'https://www.quannengcha.com'
|
||||||
|
|
||||||
|
// 本地联调 API 时,H5 仍默认走线上(web-view 无法打开 localhost)
|
||||||
|
// return 'https://www.quannengcha.com'
|
||||||
|
return 'http://127.0.0.1:5678'
|
||||||
|
}
|
||||||
@@ -17,7 +17,7 @@ export const VEHICLE_API_TITLES = {
|
|||||||
QCXG3Z3L: '车辆维保详细版查询',
|
QCXG3Z3L: '车辆维保详细版查询',
|
||||||
QCXG1H7Y: '车辆过户简版查询',
|
QCXG1H7Y: '车辆过户简版查询',
|
||||||
QCXG4I1Z: '车辆过户详版查询',
|
QCXG4I1Z: '车辆过户详版查询',
|
||||||
QCXGGB2Q: '车辆二要素核验 V1',
|
QCXGGB2Q: '车辆二要素核验简版',
|
||||||
QCXGP00W: '车辆出险详版查询',
|
QCXGP00W: '车辆出险详版查询',
|
||||||
QCXGYTS2: '人车核验(详版)',
|
QCXGYTS2: '人车核验(详版)',
|
||||||
QCXGGJ3A: '车辆 VIN 码查询号牌简版',
|
QCXGGJ3A: '车辆 VIN 码查询号牌简版',
|
||||||
|
|||||||
@@ -150,6 +150,16 @@
|
|||||||
"navigationBarTextStyle": "black"
|
"navigationBarTextStyle": "black"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"path": "pages/report/webview",
|
||||||
|
"type": "page",
|
||||||
|
"style": {
|
||||||
|
"navigationBarTitleText": "完整版报告",
|
||||||
|
"navigationStyle": "default",
|
||||||
|
"navigationBarBackgroundColor": "#ffffff",
|
||||||
|
"navigationBarTextStyle": "black"
|
||||||
|
}
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"path": "pages/toolbox/category",
|
"path": "pages/toolbox/category",
|
||||||
"type": "page",
|
"type": "page",
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ import { onLoad, onUnload } from '@dcloudio/uni-app'
|
|||||||
import { ref } from 'vue'
|
import { ref } from 'vue'
|
||||||
import { getQueryDetailByOrderId, getQueryDetailByOrderNo } from '@/api'
|
import { getQueryDetailByOrderId, getQueryDetailByOrderNo } from '@/api'
|
||||||
import VehicleReportShell from '@/components/report/VehicleReportShell.vue'
|
import VehicleReportShell from '@/components/report/VehicleReportShell.vue'
|
||||||
|
import ReportShareBar from '@/components/report/ReportShareBar.vue'
|
||||||
import { parseEncryptedQueryReport } from '@/utils/queryReportParse'
|
import { parseEncryptedQueryReport } from '@/utils/queryReportParse'
|
||||||
import { normalizeVehicleQueryData } from '@/utils/vehicleReportNormalize'
|
import { normalizeVehicleQueryData } from '@/utils/vehicleReportNormalize'
|
||||||
|
|
||||||
@@ -85,7 +86,7 @@ async function load(opts = {}) {
|
|||||||
if (parsed.ok) {
|
if (parsed.ok) {
|
||||||
queryParams.value = parsed.queryParams
|
queryParams.value = parsed.queryParams
|
||||||
rows.value = parsed.rows
|
rows.value = parsed.rows
|
||||||
errText.value = rows.value.length ? '' : '暂无报告模块数据'
|
errText.value = rows.value.length ? '' : '渲染失败,可复制底部链接在浏览器查看'
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
rows.value = normalizeVehicleQueryData([])
|
rows.value = normalizeVehicleQueryData([])
|
||||||
@@ -105,7 +106,7 @@ async function load(opts = {}) {
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<view class="page-root">
|
<view class="page-root" :class="{ 'has-share-bar': orderId || orderNo }">
|
||||||
<view v-if="loading && !pending" class="state">
|
<view v-if="loading && !pending" class="state">
|
||||||
加载中…
|
加载中…
|
||||||
</view>
|
</view>
|
||||||
@@ -124,6 +125,11 @@ async function load(opts = {}) {
|
|||||||
:rows="rows"
|
:rows="rows"
|
||||||
/>
|
/>
|
||||||
</view>
|
</view>
|
||||||
|
<ReportShareBar
|
||||||
|
v-if="orderId || orderNo"
|
||||||
|
:order-id="orderId"
|
||||||
|
:order-no="orderNo"
|
||||||
|
/>
|
||||||
</view>
|
</view>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
@@ -134,8 +140,12 @@ async function load(opts = {}) {
|
|||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.page-root.has-share-bar {
|
||||||
|
padding-bottom: calc(128rpx + env(safe-area-inset-bottom));
|
||||||
|
}
|
||||||
|
|
||||||
.state {
|
.state {
|
||||||
padding: 100rpx 32rpx;
|
padding: 48rpx 32rpx 0;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
font-size: 28rpx;
|
font-size: 28rpx;
|
||||||
color: #86909c;
|
color: #86909c;
|
||||||
|
|||||||
57
src/pages/report/webview.vue
Normal file
57
src/pages/report/webview.vue
Normal file
@@ -0,0 +1,57 @@
|
|||||||
|
<script setup>
|
||||||
|
import { onLoad } from '@dcloudio/uni-app'
|
||||||
|
import { ref } from 'vue'
|
||||||
|
|
||||||
|
definePage({
|
||||||
|
style: {
|
||||||
|
navigationBarTitleText: '完整版报告',
|
||||||
|
navigationStyle: 'default',
|
||||||
|
navigationBarBackgroundColor: '#ffffff',
|
||||||
|
navigationBarTextStyle: 'black',
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
const pageUrl = ref('')
|
||||||
|
const loadError = ref('')
|
||||||
|
|
||||||
|
onLoad((options) => {
|
||||||
|
const raw = options?.url || ''
|
||||||
|
if (!raw) {
|
||||||
|
loadError.value = '缺少报告地址'
|
||||||
|
return
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
pageUrl.value = decodeURIComponent(raw)
|
||||||
|
}
|
||||||
|
catch {
|
||||||
|
pageUrl.value = raw
|
||||||
|
}
|
||||||
|
if (!/^https:\/\//i.test(pageUrl.value)) {
|
||||||
|
loadError.value = '报告链接无效'
|
||||||
|
pageUrl.value = ''
|
||||||
|
}
|
||||||
|
})
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<view class="page">
|
||||||
|
<web-view v-if="pageUrl" :src="pageUrl" />
|
||||||
|
<view v-else class="err">
|
||||||
|
<text>{{ loadError || '无法加载报告' }}</text>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style scoped lang="scss">
|
||||||
|
.page {
|
||||||
|
width: 100%;
|
||||||
|
height: 100vh;
|
||||||
|
}
|
||||||
|
|
||||||
|
.err {
|
||||||
|
padding: 80rpx 32rpx;
|
||||||
|
text-align: center;
|
||||||
|
font-size: 28rpx;
|
||||||
|
color: #86909c;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@@ -65,17 +65,17 @@ const maskedName = computed(() => {
|
|||||||
return name.length > 1 ? name[0] + '*'.repeat(name.length - 1) : '*';
|
return name.length > 1 ? name[0] + '*'.repeat(name.length - 1) : '*';
|
||||||
});
|
});
|
||||||
|
|
||||||
// verify_code: 1 一致,2 不匹配
|
// verify_code: 1 一致,0 不一致
|
||||||
const isMatch = computed(() => {
|
const isMatch = computed(() => {
|
||||||
const code = props.data?.verify_code;
|
const n = Number(props.data?.verify_code);
|
||||||
if (code === 1) return true;
|
if (n === 1) return true;
|
||||||
if (code === 2) return false;
|
if (n === 0) return false;
|
||||||
return null; // 无有效数据时
|
return null;
|
||||||
});
|
});
|
||||||
|
|
||||||
const resultText = computed(() => {
|
const resultText = computed(() => {
|
||||||
if (isMatch.value === true) return '一致';
|
if (isMatch.value === true) return '一致';
|
||||||
if (isMatch.value === false) return '不匹配';
|
if (isMatch.value === false) return '不一致';
|
||||||
return '暂无结果';
|
return '暂无结果';
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
27
src/utils/reportH5Link.js
Normal file
27
src/utils/reportH5Link.js
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
import { generateQueryShareLink } from '@/api/query'
|
||||||
|
import { getH5Origin } from '@/config/h5'
|
||||||
|
|
||||||
|
/** 登录用户直接打开 H5 报告(需 H5 端同账号登录) */
|
||||||
|
export function buildDirectReportUrl({ orderId, orderNo }) {
|
||||||
|
const base = getH5Origin()
|
||||||
|
if (orderNo)
|
||||||
|
return `${base}/report?orderNo=${encodeURIComponent(orderNo)}`
|
||||||
|
if (orderId)
|
||||||
|
return `${base}/report?orderId=${encodeURIComponent(String(orderId))}`
|
||||||
|
return ''
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 与 H5 ShareReportButton 一致:POST /query/generate_share_link → /report/share/:id */
|
||||||
|
export async function fetchReportShareUrl({ orderId, orderNo }) {
|
||||||
|
const body = orderId
|
||||||
|
? { order_id: String(orderId) }
|
||||||
|
: { order_no: String(orderNo) }
|
||||||
|
|
||||||
|
const res = await generateQueryShareLink(body)
|
||||||
|
const linkId = res?.data?.share_link
|
||||||
|
if (res?.code !== 200 || !linkId)
|
||||||
|
throw new Error(res?.msg || '生成分享链接失败')
|
||||||
|
|
||||||
|
const base = getH5Origin()
|
||||||
|
return `${base}/report/share/${encodeURIComponent(linkId)}`
|
||||||
|
}
|
||||||
1
uni-pages.d.ts
vendored
1
uni-pages.d.ts
vendored
@@ -19,6 +19,7 @@ type _LocationUrl =
|
|||||||
"/pages/legal/privacy-policy" |
|
"/pages/legal/privacy-policy" |
|
||||||
"/pages/legal/user-agreement" |
|
"/pages/legal/user-agreement" |
|
||||||
"/pages/report/detail" |
|
"/pages/report/detail" |
|
||||||
|
"/pages/report/webview" |
|
||||||
"/pages/toolbox/category" |
|
"/pages/toolbox/category" |
|
||||||
"/pages/toolbox/index" |
|
"/pages/toolbox/index" |
|
||||||
"/pages/toolbox/query";
|
"/pages/toolbox/query";
|
||||||
|
|||||||
Reference in New Issue
Block a user