wangfukang 1 week ago
parent
commit
ae00e60a06
  1. 132
      common/fishMarketApi.js
  2. 11
      common/fishMarketSocket.js
  3. 2
      common/httpRequest.js
  4. 14
      common/ieApi.js
  5. 89
      common/ieRealNameAuth.js
  6. 47
      common/ieSocket.js

132
common/fishMarketApi.js

@ -0,0 +1,132 @@
import tui from './httpRequest'
function unwrap(res) {
if (!res) return null
if (res.success === false) {
uni.showToast({ title: res.message || '请求失败', icon: 'none', duration: 3200 })
return null
}
return res.result !== undefined ? res.result : res
}
function extractUploadUrl(fileObj) {
if (!fileObj) return ''
if (typeof fileObj === 'string') return fileObj
return fileObj.url || fileObj.fileUrl || fileObj.path || fileObj.fullPath || ''
}
function buildQuery(data = {}) {
const query = Object.keys(data)
.filter(key => data[key] !== undefined && data[key] !== null && data[key] !== '')
.map(key => encodeURIComponent(key) + '=' + encodeURIComponent(data[key]))
.join('&')
return query ? '?' + query : ''
}
export function uploadFishImage(path) {
return tui.uploadFile('/upload/file', path).then(extractUploadUrl)
}
export function pageFishGoods(data = {}) {
return tui.request('/app/fishmarket/goods/page', 'POST', data, false, false, true).then(unwrap)
}
export function pageFishWants(data = {}) {
return tui.request('/app/fishmarket/wants/page', 'POST', data, false, false, true).then(unwrap)
}
export function getFishGoodsDetail(id) {
return tui.request(`/app/fishmarket/goods/${id}`, 'GET', {}, false, true, true).then(unwrap)
}
export function publishFishGoods(data) {
return tui.request('/app/fishmarket/goods', 'POST', data, false, false, false).then(unwrap)
}
export function publishFishWant(data) {
return tui.request('/app/fishmarket/wants', 'POST', data, false, false, false).then(unwrap)
}
export function listFishCategories(regionId = '') {
return tui.request('/app/fishmarket/categories', 'GET', { regionId }, false, true, true).then(unwrap)
}
export function toggleFishFavorite(goodsId) {
return tui.request(`/app/fishmarket/goods/${goodsId}/favorite`, 'POST', {}, false, false, true).then(unwrap)
}
export function toggleFishLike(data) {
return tui.request('/app/fishmarket/like' + buildQuery(data), 'POST', {}, false, false, true).then(unwrap)
}
export function addFishComment(data) {
return tui.request('/app/fishmarket/comments', 'POST', data, false, false, false).then(unwrap)
}
export function pageFishComments(goodsId, pageNum = 1, pageSize = 10) {
return tui.request('/app/fishmarket/comments/page', 'GET', { goodsId, pageNum, pageSize }, false, true, true).then(unwrap)
}
export function deleteFishComment(id) {
return tui.request(`/app/fishmarket/comments/${id}`, 'DELETE', {}, false, false, true).then(unwrap)
}
export function submitFishComplaint(data) {
return tui.request('/app/fishmarket/complaints', 'POST', data, false, false, false).then(unwrap)
}
export function createFishChatSession(goodsId) {
return tui.request(`/app/fishmarket/goods/${goodsId}/chat`, 'POST', {}, false, false, false).then(unwrap)
}
export function getFishChatSession(sessionId) {
return tui.request(`/app/fishmarket/chat/sessions/${sessionId}`, 'GET', {}, false, true, true).then(unwrap)
}
export function pageFishChatMessages(sessionId, pageNum = 1, pageSize = 20) {
return tui.request(`/app/fishmarket/chat/sessions/${sessionId}/messages/page`, 'GET', { pageNum, pageSize }, false, true, true).then(unwrap)
}
export function sendFishChatMessage(data) {
return tui.request('/app/fishmarket/chat/messages', 'POST', data, false, false, false).then(unwrap)
}
export function pageMyFishGoods(data = {}) {
return tui.request('/app/fishmarket/my/goods', 'POST', data, false, false, true).then(unwrap)
}
export function pageMyFishWants(data = {}) {
return tui.request('/app/fishmarket/my/wants', 'POST', data, false, false, true).then(unwrap)
}
export function updateMyFishGoodsStatus(data) {
return tui.request('/app/fishmarket/my/goods/status', 'POST', data, false, false, false).then(unwrap)
}
export function updateMyFishWantStatus(data) {
return tui.request('/app/fishmarket/my/wants/status', 'POST', data, false, false, false).then(unwrap)
}
export function pageMyFishFavorites(data = {}) {
return tui.request('/app/fishmarket/my/favorites', 'POST', data, false, false, true).then(unwrap)
}
export function pageMyFishBrowse(data = {}) {
return tui.request('/app/fishmarket/my/browse', 'POST', data, false, false, true).then(unwrap)
}
export function pageMyFishSessions(data = {}) {
return tui.request('/app/fishmarket/my/sessions', 'POST', data, false, false, true).then(unwrap)
}
export function pageMyFishComments(data = {}) {
return tui.request('/app/fishmarket/my/comments', 'POST', data, false, false, true).then(unwrap)
}
export function pageMyFishLikes(data = {}) {
return tui.request('/app/fishmarket/my/likes', 'POST', data, false, false, true).then(unwrap)
}
export function pageMyFishComplaints(data = {}) {
return tui.request('/app/fishmarket/my/complaints', 'POST', data, false, false, true).then(unwrap)
}

11
common/fishMarketSocket.js

@ -0,0 +1,11 @@
import ieSocket from './ieSocket'
export default {
connect() { return ieSocket.connect() },
close() { return ieSocket.close() },
resetHandlers() { return ieSocket.resetHandlers() },
subscribeSession(sessionId) { return ieSocket.subscribeFishSession(sessionId) },
unsubscribeSession(sessionId) { return ieSocket.unsubscribeFishSession(sessionId) },
sendMessage(data) { return ieSocket.sendFishMessage(data) },
onMessage(handler) { return ieSocket.onFishMessage(handler) }
}

2
common/httpRequest.js

@ -38,7 +38,7 @@ const tui = {
//接口地址
interfaceUrl: function() {
return 'https://hbkuaishi.com/hiver' //正式
// return 'http://192.168.100.67:8888/hiver' //测试
// return 'http://192.168.100.34:8888/hiver' //测试
},
toast: function(text, duration, success) {
uni.showToast({

14
common/ieApi.js

@ -9,6 +9,18 @@ function unwrap(res) {
return res.result !== undefined ? res.result : res
}
function unwrapIeRealName(res) {
if (!res) return null
if (res.success === false) {
return {
realNameVerified: false,
verified: false,
message: res.message || '实名认证未通过,请稍后重试'
}
}
return res.result !== undefined ? res.result : res
}
function unwrapIeHome(res) {
if (!res) return null
if (res.success === false) {
@ -51,7 +63,7 @@ export function saveIeProfile(data) {
}
export function verifyIeRealName(data) {
return tui.request('/app/ie/real-name/verify', 'POST', data, false, false, true).then(unwrap)
return tui.request('/app/ie/real-name/verify', 'POST', data, false, false, true).then(unwrapIeRealName)
}
export function verifyIeStudentCard(data) {

89
common/ieRealNameAuth.js

@ -2,7 +2,17 @@ import tui from './httpRequest'
import { verifyIeRealName, verifyIeStudentCard, getIeRealNameAuditSetting } from './ieApi.js'
function showLongToast(title, duration = 3200) {
uni.showToast({ title, icon: 'none', duration })
const content = String(title || '操作未完成')
if (content.length > 18) {
uni.showModal({
title: '提示',
content,
showCancel: false,
confirmText: '知道了'
})
return
}
uni.showToast({ title: content, icon: 'none', duration })
}
function showAuthDialog(options = {}) {
@ -108,6 +118,38 @@ function promptText(title, placeholder) {
})
}
function isValidMainlandName(name) {
const value = String(name || '').trim()
if (value.length < 2 || value.length > 30) return false
if (value.indexOf('·') === 0 || value.indexOf('·') === value.length - 1 || value.indexOf('··') !== -1) return false
return /^[\u4e00-\u9fa5]+(·[\u4e00-\u9fa5]+)*$/.test(value)
}
function isValidMainlandIdCard(idCardNo) {
const id = String(idCardNo || '').trim().toUpperCase()
if (!/^\d{17}[\dX]$/.test(id)) return false
if (id.substring(0, 6) === '000000') return false
if (!isValidIdCardBirthday(id.substring(6, 14))) return false
const weights = [7, 9, 10, 5, 8, 4, 2, 1, 6, 3, 7, 9, 10, 5, 8, 4, 2]
const checks = ['1', '0', 'X', '9', '8', '7', '6', '5', '4', '3', '2']
let sum = 0
for (let i = 0; i < 17; i += 1) {
sum += Number(id.charAt(i)) * weights[i]
}
return checks[sum % 11] === id.charAt(17)
}
function isValidIdCardBirthday(birthday) {
if (!/^\d{8}$/.test(birthday)) return false
const year = Number(birthday.substring(0, 4))
const month = Number(birthday.substring(4, 6))
const day = Number(birthday.substring(6, 8))
const date = new Date(year, month - 1, day)
if (date.getFullYear() !== year || date.getMonth() !== month - 1 || date.getDate() !== day) return false
const today = new Date()
return year >= 1900 && date <= today
}
function compressImage(filePath, option) {
return new Promise(resolve => {
if (!uni.compressImage) {
@ -186,14 +228,14 @@ async function chooseFacePictureBase64() {
return lastBase64
}
function confirmAuth(actionText, cancelText) {
function confirmAuth(actionText, cancelText, dialogOptions = {}) {
return showAuthDialog({
badge: 'i/e 安全认证',
title: '进阶实名认证',
content: `为满足未成年人保护与防沉迷要求,${actionText || '继续使用'}前需要完成身份证三要素核验。`,
badge: dialogOptions.badge || 'i/e 安全认证',
title: dialogOptions.title || '进阶实名认证',
content: dialogOptions.content || `为满足未成年人保护与防沉迷要求,${actionText || '继续使用'}前需要完成身份证三要素核验。`,
confirmText: '去认证',
cancelText: cancelText || '暂不继续',
steps: [
steps: dialogOptions.steps || [
'填写身份证上的姓名与号码',
'拍摄本人清晰正脸照',
'通过后继续完善 i/e 身份资料'
@ -243,22 +285,35 @@ async function ensureStudentCardVerified(profile, options = {}) {
async function ensureAliyunRealNameVerified(profile) {
if (profile && profile.realNameVerified) return true
const regionId = getCurrentRegionId()
if (!regionId) {
showLongToast('请先选择校区后再进行实名认证', 3200)
return false
}
const certName = await promptText('填写真实姓名', '请输入身份证上的姓名')
if (!certName) {
showLongToast('未填写真实姓名,无法完成实名认证', 3200)
return false
}
const certNo = await promptText('填写身份证号', '请输入身份证号码')
if (!isValidMainlandName(certName)) {
showLongToast('真实姓名格式不正确,请填写中国大陆身份证上的中文姓名', 3600)
return false
}
const certNo = (await promptText('填写身份证号', '请输入18位中国大陆居民身份证号')).toUpperCase()
if (!certNo) {
showLongToast('未填写身份证号,无法完成实名认证', 3200)
return false
}
if (!isValidMainlandIdCard(certNo)) {
showLongToast('身份证号格式或校验位不正确,请核对后重试', 3600)
return false
}
const certPicture = await chooseFacePictureBase64()
if (!certPicture) return false
uni.showLoading({ title: '实名认证中\n正在安全核验', mask: true })
let result = null
try {
result = await verifyIeRealName({ certName, certNo, certPicture })
result = await verifyIeRealName({ certName, certNo, certPicture, regionId })
} finally {
uni.hideLoading()
}
@ -270,6 +325,20 @@ async function ensureAliyunRealNameVerified(profile) {
return true
}
function getCurrentRegionId() {
const area = uni.getStorageSync('area')
if (!area) return ''
if (typeof area === 'string') {
try {
const parsed = JSON.parse(area)
return parsed && parsed.id ? parsed.id : ''
} catch (e) {
return ''
}
}
return area.id || ''
}
function needsProfileSetup(profile) {
return !profile || profile.exists === false || profile.profileCompleted !== 1
}
@ -301,7 +370,7 @@ export async function ensureIeVerifiedBeforeAction(options = {}) {
const realNameAuditEnabled = !setting || setting.realNameAuditEnabled !== false
if (!realNameAuditEnabled) return true
const confirmed = realNameAuditEnabled
? await confirmAuth(options.actionText, options.cancelText)
? await confirmAuth(options.actionText, options.cancelText, options.authDialog || {})
: await confirmStudentCardOnly(options.actionText, options.cancelText)
if (!confirmed) return false
try {
@ -326,7 +395,7 @@ export async function ensureIeVerifiedBeforeAction(options = {}) {
}
return true
} catch (e) {
showLongToast('认证未完成,请稍后重试', 3200)
showLongToast((e && e.message) || '认证未完成,请稍后重试', 3200)
return false
}
}

47
common/ieSocket.js

@ -10,11 +10,14 @@ const socket = {
reconnectTimer: null,
reconnectAttempts: 0,
roomIds: [],
fishSessionIds: [],
messageHandlers: [],
fishMessageHandlers: [],
ackHandlers: [],
presenceHandlers: [],
roomEndHandlers: [],
offlineHandlers: []
offlineHandlers: [],
fishEnabled: false
}
function wsUrl() {
@ -86,6 +89,24 @@ function unsubscribeRoom(roomId) {
delete socket.subscriptions['ie-room-' + roomId]
}
function subscribeFishSession(sessionId) {
if (!sessionId) return false
socket.fishEnabled = true
if (socket.fishSessionIds.indexOf(sessionId) < 0) socket.fishSessionIds.push(sessionId)
if (!socket.connected || !socket.task) return false
const id = 'fish-session-' + sessionId
if (socket.subscriptions[id]) return true
socket.subscriptions[id] = true
subscribe('/topic/fishmarket/session/' + sessionId, id)
return true
}
function unsubscribeFishSession(sessionId) {
const index = socket.fishSessionIds.indexOf(sessionId)
if (index > -1) socket.fishSessionIds.splice(index, 1)
delete socket.subscriptions['fish-session-' + sessionId]
}
function bindSubscriptions() {
subscribe('/user/queue/ie/ack', 'ie-ack')
subscribe('/user/queue/ie/message', 'ie-message')
@ -101,6 +122,17 @@ function bindSubscriptions() {
subscribe('/topic/ie/room/' + roomId, id)
}
})
if (socket.fishEnabled) {
subscribe('/user/queue/fishmarket/message', 'fish-message')
send('/app/fishmarket/connect')
socket.fishSessionIds.forEach(sessionId => {
const id = 'fish-session-' + sessionId
if (!socket.subscriptions[id]) {
socket.subscriptions[id] = true
subscribe('/topic/fishmarket/session/' + sessionId, id)
}
})
}
}
function scheduleReconnect() {
@ -134,6 +166,7 @@ function handleMessage(raw) {
if (dest.indexOf('/queue/ie/presence') > -1) emit(socket.presenceHandlers, payload)
if (dest.indexOf('/queue/ie/room-end') > -1) emit(socket.roomEndHandlers, payload)
if (dest.indexOf('/queue/ie/offline') > -1) emit(socket.offlineHandlers, payload)
if (dest.indexOf('/queue/fishmarket/message') > -1 || dest.indexOf('/topic/fishmarket/session/') > -1) emit(socket.fishMessageHandlers, payload)
}
function startHeartbeat() {
@ -188,6 +221,7 @@ function close() {
socket.reconnectTimer = null
socket.reconnectAttempts = 0
socket.roomIds = []
socket.fishSessionIds = []
socket.subscriptions = {}
clearInterval(socket.heartbeatTimer)
if (socket.task) socket.task.close()
@ -197,6 +231,7 @@ function close() {
function resetHandlers() {
socket.messageHandlers = []
socket.fishMessageHandlers = []
socket.ackHandlers = []
socket.presenceHandlers = []
socket.roomEndHandlers = []
@ -209,10 +244,20 @@ export default {
resetHandlers,
subscribeRoom,
unsubscribeRoom,
subscribeFishSession,
unsubscribeFishSession,
sendMessage(data) { return send('/app/ie/message', data) },
sendFishMessage(data) {
socket.fishEnabled = true
return send('/app/fishmarket/message', data)
},
sendPresence(data) { return send('/app/ie/presence', data) },
onAck(handler) { socket.ackHandlers.push(handler) },
onMessage(handler) { socket.messageHandlers.push(handler) },
onFishMessage(handler) {
socket.fishEnabled = true
socket.fishMessageHandlers.push(handler)
},
onPresence(handler) { socket.presenceHandlers.push(handler) },
onRoomEnd(handler) { socket.roomEndHandlers.push(handler) },
onOffline(handler) { socket.offlineHandlers.push(handler) }

Loading…
Cancel
Save