start
This commit is contained in:
30
utils/api.js
Normal file
30
utils/api.js
Normal file
@@ -0,0 +1,30 @@
|
||||
const request = require('./request.js')
|
||||
|
||||
const API = {
|
||||
user: {
|
||||
wxGetPhoneNumber: (data) => request.post('/user/wxgetphonenumber', data),
|
||||
wxSignin: (data) => request.post('/user/wxsignin', data),
|
||||
signout: (data) => request.post('/user/signout', data),
|
||||
update: (data) => request.post('/user/update', data),
|
||||
},
|
||||
|
||||
escort: {
|
||||
getMyRecords: (params) => request.get('/health/escort-record/my', params),
|
||||
getAttendantRecords: (params) => request.get('/health/escort-record/attendant', params),
|
||||
getRecordById: (id) => request.get(`/health/escort-record/${id}`),
|
||||
createRecord: (data) => request.post('/health/escort-record', data),
|
||||
updateRecord: (id, data) => request.put(`/health/escort-record/${id}`, data),
|
||||
updateStatus: (id, data) => request.patch(`/health/escort-record/${id}/status`, data),
|
||||
},
|
||||
|
||||
resource: {
|
||||
getServices: (params) => request.get('/health/service', params),
|
||||
getAgreement: (params) => request.get('/health/agreement', params),
|
||||
},
|
||||
|
||||
ai: {
|
||||
chat: (data) => request.post('/ai/chat', data),
|
||||
},
|
||||
}
|
||||
|
||||
module.exports = API
|
||||
222
utils/chatmsg.js
Normal file
222
utils/chatmsg.js
Normal file
@@ -0,0 +1,222 @@
|
||||
const WS_BASE_URL = 'wss://api.huashengtec.com/health-ws'
|
||||
//const WS_BASE_URL = 'ws://127.0.0.1:9005'
|
||||
|
||||
class AIChatSocket {
|
||||
constructor(url = `${WS_BASE_URL}/chat`, options = {}) {
|
||||
this.url = url
|
||||
this.options = {
|
||||
timeout: 10000,
|
||||
heartbeatInterval: 30000,
|
||||
autoReconnect: true,
|
||||
maxReconnectAttempts: 3,
|
||||
reconnectDelay: 3000,
|
||||
...options
|
||||
}
|
||||
|
||||
this.socketTask = null
|
||||
this.isConnected = false
|
||||
this.isConnecting = false
|
||||
this.messageQueue = []
|
||||
this.reconnectAttempts = 0
|
||||
|
||||
this._openCallback = null
|
||||
this._closeCallback = null
|
||||
this._errorCallback = null
|
||||
this._messageCallback = null
|
||||
this._heartbeatTimer = null
|
||||
}
|
||||
|
||||
connect() {
|
||||
if (this.isConnected || this.isConnecting) {
|
||||
console.log('[AIChatSocket] Already connected or connecting')
|
||||
return Promise.resolve()
|
||||
}
|
||||
|
||||
this.isConnecting = true
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
this.socketTask = wx.connectSocket({
|
||||
url: this.url,
|
||||
header: {
|
||||
'content-type': 'application/json',
|
||||
...this.options.header
|
||||
},
|
||||
protocols: this.options.protocols || [],
|
||||
success: () => {
|
||||
console.log('[AIChatSocket] WebSocket connecting...')
|
||||
},
|
||||
fail: (err) => {
|
||||
this.isConnecting = false
|
||||
console.error('[AIChatSocket] Connect failed:', err)
|
||||
reject(err)
|
||||
}
|
||||
})
|
||||
|
||||
if (!this.socketTask) {
|
||||
this.isConnecting = false
|
||||
reject(new Error('SocketTask creation failed'))
|
||||
return
|
||||
}
|
||||
|
||||
this.socketTask.onOpen(() => {
|
||||
console.log('[AIChatSocket] Connection opened')
|
||||
this.isConnected = true
|
||||
this.isConnecting = false
|
||||
this.reconnectAttempts = 0
|
||||
this._startHeartbeat()
|
||||
|
||||
this._flushMessageQueue()
|
||||
|
||||
if (this._openCallback) {
|
||||
this._openCallback()
|
||||
}
|
||||
resolve()
|
||||
})
|
||||
|
||||
this.socketTask.onClose((res) => {
|
||||
console.log('[AIChatSocket] Connection closed:', res)
|
||||
this.isConnected = false
|
||||
this.isConnecting = false
|
||||
this._stopHeartbeat()
|
||||
|
||||
if (this._closeCallback) {
|
||||
this._closeCallback(res)
|
||||
}
|
||||
|
||||
if (this.options.autoReconnect && this.reconnectAttempts < this.options.maxReconnectAttempts) {
|
||||
this._reconnect()
|
||||
}
|
||||
})
|
||||
|
||||
this.socketTask.onError((err) => {
|
||||
console.error('[AIChatSocket] WebSocket error:', err)
|
||||
this.isConnected = false
|
||||
this.isConnecting = false
|
||||
|
||||
if (this._errorCallback) {
|
||||
this._errorCallback(err)
|
||||
}
|
||||
})
|
||||
|
||||
this.socketTask.onMessage((res) => {
|
||||
try {
|
||||
const data = typeof res.data === 'string' ? JSON.parse(res.data) : res.data
|
||||
if (this._messageCallback) {
|
||||
this._messageCallback(data)
|
||||
}
|
||||
} catch (e) {
|
||||
if (this._messageCallback) {
|
||||
this._messageCallback(res.data)
|
||||
}
|
||||
}
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
send(data) {
|
||||
const message = typeof data === 'string' ? data : JSON.stringify(data)
|
||||
|
||||
if (!this.isConnected || !this.socketTask) {
|
||||
console.log('[AIChatSocket] Not connected, queueing message')
|
||||
this.messageQueue.push(message)
|
||||
return false
|
||||
}
|
||||
|
||||
try {
|
||||
this.socketTask.send({
|
||||
data: message,
|
||||
fail: (err) => {
|
||||
console.error('[AIChatSocket] Send failed:', err)
|
||||
this.messageQueue.push(message)
|
||||
}
|
||||
})
|
||||
return true
|
||||
} catch (err) {
|
||||
console.error('[AIChatSocket] Send error:', err)
|
||||
this.messageQueue.push(message)
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
close() {
|
||||
this._stopHeartbeat()
|
||||
this.options.autoReconnect = false
|
||||
|
||||
if (this.socketTask) {
|
||||
this.socketTask.close({
|
||||
code: 1000,
|
||||
reason: 'User closed',
|
||||
fail: (err) => {
|
||||
console.error('[AIChatSocket] Close failed:', err)
|
||||
}
|
||||
})
|
||||
this.socketTask = null
|
||||
}
|
||||
|
||||
this.isConnected = false
|
||||
this.isConnecting = false
|
||||
this.messageQueue = []
|
||||
}
|
||||
|
||||
onOpen(callback) {
|
||||
this._openCallback = callback
|
||||
}
|
||||
|
||||
onClose(callback) {
|
||||
this._closeCallback = callback
|
||||
}
|
||||
|
||||
onError(callback) {
|
||||
this._errorCallback = callback
|
||||
}
|
||||
|
||||
onMessage(callback) {
|
||||
this._messageCallback = callback
|
||||
}
|
||||
|
||||
_flushMessageQueue() {
|
||||
if (this.messageQueue.length === 0) return
|
||||
|
||||
console.log(`[AIChatSocket] Flushing ${this.messageQueue.length} queued messages`)
|
||||
while (this.messageQueue.length > 0) {
|
||||
const message = this.messageQueue.shift()
|
||||
this.send(message)
|
||||
}
|
||||
}
|
||||
|
||||
_reconnect() {
|
||||
this.reconnectAttempts++
|
||||
console.log(`[AIChatSocket] Reconnecting... Attempt ${this.reconnectAttempts}/${this.options.maxReconnectAttempts}`)
|
||||
|
||||
setTimeout(() => {
|
||||
this.connect().catch((err) => {
|
||||
console.error('[AIChatSocket] Reconnect failed:', err)
|
||||
})
|
||||
}, this.options.reconnectDelay)
|
||||
}
|
||||
|
||||
_startHeartbeat() {
|
||||
this._stopHeartbeat()
|
||||
|
||||
this._heartbeatTimer = setInterval(() => {
|
||||
if (this.isConnected && this.socketTask) {
|
||||
this.socketTask.send({
|
||||
data: JSON.stringify({ type: 'ping' }),
|
||||
fail: (err) => {
|
||||
console.error('[AIChatSocket] Heartbeat failed:', err)
|
||||
this._stopHeartbeat()
|
||||
}
|
||||
})
|
||||
}
|
||||
}, this.options.heartbeatInterval)
|
||||
}
|
||||
|
||||
_stopHeartbeat() {
|
||||
if (this._heartbeatTimer) {
|
||||
clearInterval(this._heartbeatTimer)
|
||||
this._heartbeatTimer = null
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = AIChatSocket
|
||||
20
utils/eventBus.js
Normal file
20
utils/eventBus.js
Normal file
@@ -0,0 +1,20 @@
|
||||
export default function createBus() {
|
||||
return {
|
||||
events: {},
|
||||
on(event, callback) {
|
||||
if (!this.events[event]) this.events[event] = [];
|
||||
this.events[event].push(callback);
|
||||
},
|
||||
off(event, callback) {
|
||||
if (!this.events[event]) return;
|
||||
if (!callback) this.events[event] = [];
|
||||
else {
|
||||
const index = this.events[event].indexOf(callback);
|
||||
if (index !== -1) this.events[event].splice(index, 1);
|
||||
}
|
||||
},
|
||||
emit(event, ...args) {
|
||||
if (this.events[event]) this.events[event].forEach((callback) => callback(...args));
|
||||
},
|
||||
};
|
||||
}
|
||||
52
utils/request.js
Normal file
52
utils/request.js
Normal file
@@ -0,0 +1,52 @@
|
||||
class Request {
|
||||
|
||||
constructor(baseURL = 'https://api.huashengtec.com') {
|
||||
//constructor(baseURL = 'http://127.0.0.1:9004') {
|
||||
this.baseURL = baseURL
|
||||
}
|
||||
|
||||
request(options) {
|
||||
return new Promise((resolve, reject) => {
|
||||
const { url, method = 'GET', data = {}, header = {}, ...rest } = options
|
||||
|
||||
const app = getApp()
|
||||
const token = app?.globalData?.user?.security?.token || ''
|
||||
|
||||
data.appId = 'wxapp-escort'
|
||||
|
||||
wx.request({
|
||||
url: url.startsWith('http') ? url : `${this.baseURL}${url}`,
|
||||
method,
|
||||
data,
|
||||
header: {
|
||||
'Content-Type': 'application/json',
|
||||
...(token ? { 'token': token } : {}),
|
||||
...header
|
||||
},
|
||||
...rest,
|
||||
success: (res) => {
|
||||
if (res.statusCode >= 200 && res.statusCode < 300) {
|
||||
resolve(res.data)
|
||||
} else {
|
||||
reject(new Error(`HTTP ${res.statusCode}`))
|
||||
}
|
||||
},
|
||||
fail: (err) => {
|
||||
reject(err)
|
||||
}
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
get(url, params = {}, options = {}) {
|
||||
return this.request({ url, method: 'GET', data: params, ...options })
|
||||
}
|
||||
|
||||
post(url, data = {}, options = {}) {
|
||||
return this.request({ url, method: 'POST', data, ...options })
|
||||
}
|
||||
}
|
||||
|
||||
const request = new Request()
|
||||
|
||||
module.exports = request
|
||||
28
utils/util.js
Normal file
28
utils/util.js
Normal file
@@ -0,0 +1,28 @@
|
||||
const formatNumber = (n) => {
|
||||
n = n.toString();
|
||||
return n[1] ? n : `0${n}`;
|
||||
};
|
||||
|
||||
const formatTime = (date) => {
|
||||
const year = date.getFullYear();
|
||||
const month = date.getMonth() + 1;
|
||||
const day = date.getDate();
|
||||
const hour = date.getHours();
|
||||
const minute = date.getMinutes();
|
||||
const second = date.getSeconds();
|
||||
|
||||
return `${[year, month, day].map(formatNumber).join('/')} ${[hour, minute, second].map(formatNumber).join(':')}`;
|
||||
};
|
||||
|
||||
// 复制到本地临时路径,方便预览
|
||||
const getLocalUrl = (path, name) => {
|
||||
const fs = wx.getFileSystemManager();
|
||||
const tempFileName = `${wx.env.USER_DATA_PATH}/${name}`;
|
||||
fs.copyFileSync(path, tempFileName);
|
||||
return tempFileName;
|
||||
};
|
||||
|
||||
module.exports = {
|
||||
formatTime,
|
||||
getLocalUrl,
|
||||
};
|
||||
Reference in New Issue
Block a user