From 7b516404cee6eeb012ee8d8b6cbd173e45cd6fbe Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=B5=85=E5=BF=B5?= Date: Fri, 16 Jan 2026 09:54:29 +0800 Subject: [PATCH] =?UTF-8?q?=E8=B0=83=E6=95=B4=20=E6=B7=BB=E5=8A=A0?= =?UTF-8?q?=E8=B4=B8=E6=98=93=E6=9D=A1=E6=AC=BE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- components/CarCard/CarCard.vue | 44 +- pages/index/changinfo.vue | 12 +- pages/index/detils.vue | 333 ++++++- pages/index/index.vue | 281 +++++- pages/index/mine - 副本.vue | 118 ++- pages/index/mine.vue | 351 ++++++- pages/index/myPublish.vue | 280 ++++-- pages/index/publish.vue | 144 ++- pages/index/publishedit.vue | 1544 ++++++++++++++++++------------- pages/login/feishu-callback.vue | 2 +- pages/login/index.vue | 14 +- 11 files changed, 2316 insertions(+), 807 deletions(-) diff --git a/components/CarCard/CarCard.vue b/components/CarCard/CarCard.vue index e2868a0..2665050 100644 --- a/components/CarCard/CarCard.vue +++ b/components/CarCard/CarCard.vue @@ -1,7 +1,15 @@ @@ -44,7 +101,6 @@ diff --git a/pages/index/mine - 副本.vue b/pages/index/mine - 副本.vue index c5b4a8b..fed412c 100644 --- a/pages/index/mine - 副本.vue +++ b/pages/index/mine - 副本.vue @@ -79,6 +79,7 @@ } }, onLoad() { + this.initFeishuShare() // H5:处理分享兜底参数 r(如果路由没命中/经历登录回跳,会先落到首页) // #ifdef H5 try { @@ -98,6 +99,89 @@ // #endif }, methods: { + isFeishuEnv() { + // 飞书/ Lark 客户端内置浏览器 UA 通常包含 Feishu / Lark + try { + const ua = (navigator.userAgent || '').toLowerCase() + return ua.includes('feishu') || ua.includes('lark') + } catch (e) { + return false + } + }, + + loadFeishuJSSDK() { + // 动态加载飞书 H5 JS-SDK(避免你还要改 public/index.html) + return new Promise((resolve, reject) => { + try { + // 已加载 + if (typeof window !== 'undefined' && window.h5sdk && window.tt) return resolve(true) + // H5 才有 document + if (typeof document === 'undefined') return reject(new Error('not in h5 environment')) + // 已插入但未 ready + const existed = document.querySelector('script[data-feishu-h5sdk="1"]') + if (existed) { + existed.addEventListener('load', () => resolve(true)) + existed.addEventListener('error', () => reject(new Error('feishu sdk load error'))) + return + } + const s = document.createElement('script') + s.async = true + s.src = 'https://lf-scm-cn.feishucdn.com/lark/op/h5-js-sdk-1.5.44.js' + s.onload = () => resolve(true) + s.onerror = () => reject(new Error('feishu sdk load error')) + document.head.appendChild(s) + } catch (e) { + reject(e) + } + }) + }, + getFeishuSignUrl() { + // 飞书签名通常要求“去掉 hash 的完整 URL” + try { + return window.location.href.split('#')[0] + } catch (e) { + return '' + } + }, + initFeishuShare() { + try { + // 确保在飞书环境 + // if (!this.isFeishuEnv()) return + // 动态加载 SDK + this.loadFeishuJSSDK() + + // 这里需要后端提供签名接口:返回 { appId, timestamp, nonceStr, signature } + // 你可以按你后端习惯改成:request({ url: 'xxx', ... }) + // const signUrl = encodeURIComponent(this.getFeishuSignUrl()) + const signUrl = this.getFeishuSignUrl() + + request({ + url:'common/auth/feishu/signature', + method:'get', + data: {url:signUrl,app_id:uni.getStorageSync('fsappid')} + }).then(res => { + var cfg = res.data.data; + window.h5sdk.config({ + appId: cfg.appId || uni.getStorageSync('fsappid'), + timestamp: cfg.timestamp, + nonceStr: cfg.nonceStr, + signature: cfg.signature, + jsApiList: ['shareWebContent','share'] + }) + + window.h5sdk.ready(() => { + this._feishuReady = true + }) + window.h5sdk.error((err) => { + this._feishuReady = false + console.error('Feishu JSSDK error:', err) + }) + }) + } catch (e) { + // 不要阻塞页面,失败就走 H5 的兜底分享 + console.error('initFeishuShare failed:', e) + } + }, onRequestPrice(payload) { // payload: { item, index } this.priceDialogItem = payload && payload.item ? payload.item : null @@ -107,6 +191,32 @@ this.$refs.inputDialog && this.$refs.inputDialog.open() }) }, + // H5 下载:用 a 标签触发 + downloadByAnchor(url, filename) { + try { + const a = document.createElement('a') + a.href = url + a.download = filename || '' + a.target = '_blank' + document.body.appendChild(a) + a.click() + document.body.removeChild(a) + } catch (e) { + // 兜底:直接打开 + if (typeof window !== 'undefined') window.open(url, '_blank') + } + }, + downloadpdf(item) { + request({ + url: 'common/usedcar/pdf', + method: 'get', + data: { id: item.id } + }).then(res => { + if (res.data.code == 200) { + this.downloadByAnchor(res.data.data.pdf_url, res.data.data.file_name) + } + }) + }, dialogInputConfirm(val) { const item = this.priceDialogItem const index = this.priceDialogIndex @@ -130,13 +240,7 @@ if (res.data.code == 200) { // 通知刷新列表(你原来就是靠这个事件刷新) this.onSearch() - - // 直接调用对应卡片实例的下载方法(如果 ref 数组存在的话) - const cards = this.$refs.carCard - const card = Array.isArray(cards) ? cards[index] : cards - if (card && typeof card.downloadpdf === 'function') { - card.downloadpdf(item) - } + this.downloadpdf(item) } else { uni.showToast({ title: res.data.msg || '生成失败', icon: 'none' }) } diff --git a/pages/index/mine.vue b/pages/index/mine.vue index fed412c..f2154e1 100644 --- a/pages/index/mine.vue +++ b/pages/index/mine.vue @@ -26,6 +26,7 @@ > @@ -33,13 +34,61 @@ - + + 设置价格 + + 贸易条款 + + + + + + 价格 + + + + + + + + + + + + + + 语言 + + + + + + + + 取消 + 确认 + + @@ -62,12 +111,6 @@ style: { backgroundColor: '#007aff' } - }, - { - text: '删除', - style: { - backgroundColor: '#F56C6C' - } } ], keyword: '', @@ -75,7 +118,35 @@ pageSize: 10, loading: false, finished: false, - list: [] + list: [], + priceForm: { + trade_term:'', + price: "", // 只存数字字符串 + currency: "USD", // USD | RUB | AED | EUR + lang: "en" // en | ru | es | ar + }, + currencyOptions: [ + { value: "USD", text: "美元" }, + { value: "CNY", text: "人民币" }, + { value: "RUB", text: "卢布" }, + { value: "AED", text: "迪拉姆" }, + { value: "EUR", text: "欧元" } + ], + langOptions: [ + { text: "英语", value: "en" }, + { text: "俄语", value: "ru" }, + { text: "西班牙语", value: "es" }, + { text: "阿拉伯语", value: "ar" } + ], + tradeTermOptions: [ + { value: "FOB", text: "FOB" }, + { value: "CIF", text: "CIF" }, + { value: "EXW", text: "EXW" }, + { value: "DDP", text: "DDP" }, + { value: "CIP", text: "CIP" }, + { value: "FCA", text: "FCA" }, + { value: "CFR", text: "CFR" } + ] } }, onLoad() { @@ -187,6 +258,12 @@ this.priceDialogItem = payload && payload.item ? payload.item : null this.priceDialogIndex = payload && typeof payload.index === 'number' ? payload.index : -1 this.priceDialogValue = '' + this.priceForm = { + trade_term:'', + price:"", + currency: "USD", + lang: "en" + } this.$nextTick(() => { this.$refs.inputDialog && this.$refs.inputDialog.open() }) @@ -217,29 +294,77 @@ } }) }, + closePriceDialog() { + this.$refs.inputDialog.close() + }, + + // 只允许数字 + 可选1个小数点(你要“纯整数”也行,我后面给你一行改法) + onPriceInput(e) { + let v = (e.detail && e.detail.value) ? String(e.detail.value) : String(this.priceForm.price || "") + + // 过滤掉非数字和点 + v = v.replace(/[^\d.]/g, "") + + // 只保留第一个小数点 + const parts = v.split(".") + if (parts.length > 2) { + v = parts[0] + "." + parts.slice(1).join("") + } + + // 去掉开头多余 0(保留 0.xxx) + v = v.replace(/^0+(\d)/, "$1") + if (v.startsWith(".")) v = "0" + v + + this.priceForm.price = v + }, + + onCurrencyPickerChange(e) { + const idx = Number(e.detail.value || 0) + this.currencyIndex = idx + this.priceForm.currency = this.currencyOptions[idx]?.value || "USD" + }, + + onLangChange(e) { + this.priceForm.lang = e.detail.value + }, + + confirmPriceDialog() { + if (!this.priceForm.trade_term) { + return uni.showToast({ title: "请选择贸易条款", icon: "none" }) + } + // 校验 + if (!this.priceForm.price) { + return uni.showToast({ title: "请输入价格", icon: "none" }) + } + + const payload = { + trade_term:this.priceForm.trade_term, + price: this.priceForm.price, // 数字字符串 + currency: this.priceForm.currency, // USD/RUB/AED/EUR + lang: this.priceForm.lang // en/ru/es/ar + } + console.log(payload) + this.closePriceDialog() + this.dialogInputConfirm(payload) + }, dialogInputConfirm(val) { const item = this.priceDialogItem const index = this.priceDialogIndex - const price = String(val || '').trim() if (!item) return - if (!price) { + if (!val.price) { uni.showToast({ title: '请输入价格', icon: 'none' }) return } - if (isNaN(price) || Number(price) <= 0) { - uni.showToast({ title: '请输入有效的价格', icon: 'none' }) - return - } - request({ url: 'common/usedcar/produce/pdf', method: 'get', - data: { id: item.id, price } + data: { id: item.id, price:val.price,currency:val.currency,lang:val.lang,trade_term:val.trade_term } }).then(res => { if (res.data.code == 200) { // 通知刷新列表(你原来就是靠这个事件刷新) this.onSearch() + this.downloadpdf(item) } else { uni.showToast({ title: res.data.msg || '生成失败', icon: 'none' }) @@ -287,40 +412,48 @@ let { content } = e; - if (content.text === '删除') { - uni.showModal({ - title: '提示', - content: '是否删除', - success: res => { - if (res.confirm) { - request({ - url:'common/usedcar/destroy', - method:'post', - data: {id:item.id} - }).then(res => { - uni.showToast({ - title: res.data.message, - icon: 'none' - }); - this.queryList() - }) - } else if (res.cancel) { - console.log('用户点击取消'); - } - } - }); - } else { - const id = item.id - uni.navigateTo({ - url: `/pages/index/publishedit?id=${id}` - }) - } + const id = item.id + uni.navigateTo({ + url: `/pages/index/publishedit?id=${id}` + }) + // if (content.text === '删除') { + // uni.showModal({ + // title: '提示', + // content: '是否删除', + // success: res => { + // if (res.confirm) { + // request({ + // url:'common/usedcar/destroy', + // method:'post', + // data: {id:item.id} + // }).then(res => { + // uni.showToast({ + // title: res.data.message, + // icon: 'none' + // }); + // this.queryList() + // }) + // } else if (res.cancel) { + // console.log('用户点击取消'); + // } + // } + // }); + // } else { + // const id = item.id + // uni.navigateTo({ + // url: `/pages/index/publishedit?id=${id}` + // }) + // } } } } diff --git a/pages/index/myPublish.vue b/pages/index/myPublish.vue index 9f5786d..b697274 100644 --- a/pages/index/myPublish.vue +++ b/pages/index/myPublish.vue @@ -1,34 +1,22 @@ @@ -55,18 +54,22 @@ }, data() { return { + priceDialogItem: null, + priceDialogIndex: -1, + priceDialogValue: '', options1: [{ - text: '编辑', - style: { - backgroundColor: '#007aff' + text: '编辑', + style: { + backgroundColor: '#007aff' + } + }, + { + text: '删除', + style: { + backgroundColor: '#F56C6C' + } } - }, - { - text: '删除', - style: { - backgroundColor: '#F56C6C' - } - }], + ], keyword: '', page: 1, pageSize: 10, @@ -76,48 +79,211 @@ } }, onLoad() { + this.initFeishuShare() + // H5:处理分享兜底参数 r(如果路由没命中/经历登录回跳,会先落到首页) + // #ifdef H5 + try { + const u = new URL(window.location.href) + const r = u.searchParams.get('r') + if (r) { + const target = decodeURIComponent(r) + // 清理地址栏的 r,避免反复跳转 + u.searchParams.delete('r') + window.history.replaceState({}, '', u.toString()) + // 让首页加载完再跳 + setTimeout(() => { + uni.navigateTo({ url: target }) + }, 50) + } + } catch (e) {} + // #endif }, methods: { - onKeywordChange(val) { - // val 是输入值(uView 通常会传) - this.keyword = val + isFeishuEnv() { + // 飞书/ Lark 客户端内置浏览器 UA 通常包含 Feishu / Lark + try { + const ua = (navigator.userAgent || '').toLowerCase() + return ua.includes('feishu') || ua.includes('lark') + } catch (e) { + return false + } + }, - // 防抖:300ms 内持续输入只触发一次 - if (this._kwTimer) clearTimeout(this._kwTimer) - this._kwTimer = setTimeout(() => { - this.onSearch() - }, 300) + loadFeishuJSSDK() { + // 动态加载飞书 H5 JS-SDK(避免你还要改 public/index.html) + return new Promise((resolve, reject) => { + try { + // 已加载 + if (typeof window !== 'undefined' && window.h5sdk && window.tt) return resolve(true) + // H5 才有 document + if (typeof document === 'undefined') return reject(new Error('not in h5 environment')) + // 已插入但未 ready + const existed = document.querySelector('script[data-feishu-h5sdk="1"]') + if (existed) { + existed.addEventListener('load', () => resolve(true)) + existed.addEventListener('error', () => reject(new Error('feishu sdk load error'))) + return + } + const s = document.createElement('script') + s.async = true + s.src = 'https://lf-scm-cn.feishucdn.com/lark/op/h5-js-sdk-1.5.44.js' + s.onload = () => resolve(true) + s.onerror = () => reject(new Error('feishu sdk load error')) + document.head.appendChild(s) + } catch (e) { + reject(e) + } + }) + }, + getFeishuSignUrl() { + // 飞书签名通常要求“去掉 hash 的完整 URL” + try { + return window.location.href.split('#')[0] + } catch (e) { + return '' + } + }, + initFeishuShare() { + try { + // 确保在飞书环境 + // if (!this.isFeishuEnv()) return + // 动态加载 SDK + this.loadFeishuJSSDK() + + // 这里需要后端提供签名接口:返回 { appId, timestamp, nonceStr, signature } + // 你可以按你后端习惯改成:request({ url: 'xxx', ... }) + // const signUrl = encodeURIComponent(this.getFeishuSignUrl()) + const signUrl = this.getFeishuSignUrl() + + request({ + url:'common/auth/feishu/signature', + method:'get', + data: {url:signUrl,app_id:uni.getStorageSync('fsappid')} + }).then(res => { + var cfg = res.data.data; + window.h5sdk.config({ + appId: cfg.appId || uni.getStorageSync('fsappid'), + timestamp: cfg.timestamp, + nonceStr: cfg.nonceStr, + signature: cfg.signature, + jsApiList: ['shareWebContent','share'] + }) + + window.h5sdk.ready(() => { + this._feishuReady = true + }) + window.h5sdk.error((err) => { + this._feishuReady = false + console.error('Feishu JSSDK error:', err) + }) + }) + } catch (e) { + // 不要阻塞页面,失败就走 H5 的兜底分享 + console.error('initFeishuShare failed:', e) + } + }, + onRequestPrice(payload) { + // payload: { item, index } + this.priceDialogItem = payload && payload.item ? payload.item : null + this.priceDialogIndex = payload && typeof payload.index === 'number' ? payload.index : -1 + this.priceDialogValue = '' + this.$nextTick(() => { + this.$refs.inputDialog && this.$refs.inputDialog.open() + }) + }, + // H5 下载:用 a 标签触发 + downloadByAnchor(url, filename) { + try { + const a = document.createElement('a') + a.href = url + a.download = filename || '' + a.target = '_blank' + document.body.appendChild(a) + a.click() + document.body.removeChild(a) + } catch (e) { + // 兜底:直接打开 + if (typeof window !== 'undefined') window.open(url, '_blank') + } + }, + downloadpdf(item) { + request({ + url: 'common/usedcar/pdf', + method: 'get', + data: { id: item.id } + }).then(res => { + if (res.data.code == 200) { + this.downloadByAnchor(res.data.data.pdf_url, res.data.data.file_name) + } + }) + }, + dialogInputConfirm(val) { + const item = this.priceDialogItem + const index = this.priceDialogIndex + const price = String(val || '').trim() + + if (!item) return + if (!price) { + uni.showToast({ title: '请输入价格', icon: 'none' }) + return + } + if (isNaN(price) || Number(price) <= 0) { + uni.showToast({ title: '请输入有效的价格', icon: 'none' }) + return + } + + request({ + url: 'common/usedcar/produce/pdf', + method: 'get', + data: { id: item.id, price } + }).then(res => { + if (res.data.code == 200) { + // 通知刷新列表(你原来就是靠这个事件刷新) + this.onSearch() + this.downloadpdf(item) + } else { + uni.showToast({ title: res.data.msg || '生成失败', icon: 'none' }) + } + }) + }, + onKeywordChange(val) { + // val 是输入值(uView 通常会传) + this.keyword = val + + // 防抖:300ms 内持续输入只触发一次 + if (this._kwTimer) clearTimeout(this._kwTimer) + this._kwTimer = setTimeout(() => { + this.onSearch() + }, 300) }, onSearch() { - this.queryList(this.page, this.pageSize) + this.queryList(this.page,this.pageSize) }, queryList(pageNo, pageSize, from) { this.loading = true; var that = this; const params = { - current: pageNo, - status: 1, - size: 10, - scene: 'self' // 只获取自己的发布 + current:pageNo, + status:1, + size:10 }; params.keyword = this.keyword; + params.scene = 'self'; request({ - url: 'common/usedcar/list', - method: 'get', + url:'common/usedcar/list', + method:'get', data: params }).then(res => { - if (res.data.code == 200) { + if(res.data.code ==200){ var datas = res.data.data.records; this.$refs.paging.complete(datas); - } else { + }else{ } uni.stopPullDownRefresh(); + // }) }, - goBack() { - uni.navigateBack() - }, - swipeClick(e, item) { + swipeClick(e,item){ let { content } = e; @@ -128,9 +294,9 @@ success: res => { if (res.confirm) { request({ - url: 'common/usedcar/destroy', - method: 'post', - data: { id: item.id } + url:'common/usedcar/destroy', + method:'post', + data: {id:item.id} }).then(res => { uni.showToast({ title: res.data.message, @@ -165,6 +331,8 @@ width: 100%; bottom: 0px; z-index: 99; + // padding: 28rpx 24rpx 18rpx; + // background: linear-gradient(180deg, rgba(255, 151, 47, 0.22) 0%, rgba(255, 151, 47, 0.06) 55%, #f4f6f8 100%); } .head-search { diff --git a/pages/index/publish.vue b/pages/index/publish.vue index 865367d..42412f2 100644 --- a/pages/index/publish.vue +++ b/pages/index/publish.vue @@ -1,5 +1,6 @@ + + + /* H5 自定义选择器:用于突破 9 个限制(H5 最多 20) */ + .h5-picker-grid{ + display:flex; + flex-wrap:wrap; + gap: 16rpx; + align-items:flex-start; + } + .h5-thumb{ + width: 210rpx; + height: 210rpx; + border-radius: 12rpx; + overflow:hidden; + position: relative; + background: #f6f6f6; + } + .h5-thumb-img{ + width: 100%; + height: 100%; + } + .h5-thumb-del{ + position:absolute; + right: 8rpx; + top: 8rpx; + background: rgba(0,0,0,0.45); + color:#fff; + font-size: 22rpx; + padding: 6rpx 10rpx; + border-radius: 999rpx; + } + .h5-count{ + margin-top: 8rpx; + font-size: 22rpx; + color:#999; + text-align:center; + } + .h5-attach-grid .h5-attach{ + width: 210rpx; + min-height: 120rpx; + padding: 16rpx; + border: 1px solid #eee; + border-radius: 12rpx; + background: #fafafa; + position: relative; + } + .h5-attach-name{ + font-size: 24rpx; + color:#333; + word-break: break-all; + padding-right: 60rpx; + } + \ No newline at end of file diff --git a/pages/index/publishedit.vue b/pages/index/publishedit.vue index fad8644..1a678a6 100644 --- a/pages/index/publishedit.vue +++ b/pages/index/publishedit.vue @@ -1,5 +1,5 @@