优化问题

This commit is contained in:
Leo_Ding 2025-08-12 09:33:22 +08:00
parent f8b3520e5d
commit 2a48964efb
11 changed files with 512 additions and 197 deletions

View File

@ -0,0 +1,150 @@
<template>
<!-- 自定义顶部返回栏 -->
<view class="custom-back-header" :style="headerStyle">
<!-- 返回按钮 -->
<view class="back-btn" @click="handleBack">
<slot name="icon">
<!-- 默认返回图标 -->
<view class="icon"></view>
</slot>
<text v-if="showText" class="text">{{ backText }}</text>
</view>
<!-- 标题插槽 -->
<view class="title">
<slot>{{ title }}</slot>
</view>
<!-- 右侧插槽 -->
<view class="right-slot">
<slot name="right"></slot>
</view>
</view>
</template>
<script>
export default {
props: {
//
title: {
type: String,
default: ''
},
//
showText: {
type: Boolean,
default: true
},
//
backText: {
type: String,
default: '返回'
},
//
bgColor: {
type: String,
default: '#ffffff'
},
//
color: {
type: String,
default: '#333333'
},
//
immersive: {
type: Boolean,
default: true
},
//
targetPath: {
type: String,
default: ''
}
},
computed: {
headerStyle() {
return {
backgroundColor: this.bgColor,
color: this.color,
paddingTop: this.immersive ? 'var(--status-bar-height)' : '0'
};
}
},
methods: {
handleBack() {
if (this.$listeners.back) {
// back
this.$emit('back');
return;
}
const pages = getCurrentPages();
//
if (this.targetPath) {
const target = pages.find(page =>
page.route === this.targetPath.replace(/^\//, '')
);
if (target) {
const delta = pages.length - pages.indexOf(target) - 1;
uni.navigateBack({ delta });
} else {
uni.redirectTo({ url: this.targetPath });
}
return;
}
//
if (pages.length >= 2) {
uni.navigateBack();
} else {
uni.switchTab({ url: '/pages/index/index' });
}
}
}
};
</script>
<style scoped>
.custom-back-header {
display: flex;
align-items: center;
height: 44px;
padding: 0 15px;
position: relative;
z-index: 999;
}
.back-btn {
display: flex;
align-items: center;
padding: 5px 10px 5px 0;
margin-right: 10px;
}
.icon {
font-size: 20px;
margin-right: 5px;
}
.text {
font-size: 16px;
}
.title {
flex: 1;
text-align: center;
font-size: 17px;
font-weight: bold;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.right-slot {
min-width: 60px;
display: flex;
justify-content: flex-end;
}
</style>

View File

@ -172,9 +172,10 @@
//
{
"path": "pages/meetingList/index",
"style": {
"navigationBarTitleText": "近山社区",
"navigationStyle": "custom" //
"style": {
"navigationStyle": "default",
"navigationBarTitleText": "近山社区"
// "navigationStyle": "custom" //
}
},
//
@ -206,18 +207,21 @@
{
"path": "pages/sign/sign",
"style": {
"navigationStyle": "default",
"navigationBarTitleText": "电子签名"
}
},
{
"path": "pages/docList/index",
"style": {
"navigationStyle": "default",
"navigationBarTitleText": "文件下载"
}
}
],
"globalStyle": {
"navigationBarTextStyle": "black",
"navigationBarBackgroundColor": "#F8F8F8",
"backgroundColor": "#F8F8F8"

View File

@ -84,25 +84,40 @@
</scroll-view>
<!-- 输入区域 -->
<view class="chat-input">
<view class="" style="flex: 1;">
<input class="input-field" placeholder="输入消息..." v-model="inputMsg" @confirm="sendMessage"
confirm-type="send" />
</view>
<view class="" style="width: 100px;">
<u-button type="primary" :disabled="!inputMsg.trim()||isAnswering" @click="sendMessage" shape="circle">
发送
</u-button>
<view class="chat-bottom">
<view class="" style="padding: 10px;">
<view class="aiTag" v-if="aiName==='生活咨询'" @click="sendMessageCeshi(0)">
最近雨季来了家里总是很潮湿有什么简单有效的除湿防霉小妙招吗
</view>
<view class="aiTag" v-if="aiName==='穿搭顾问'" @click="sendMessageCeshi(1)">
我下周要参加一个商务休闲风格的客户午餐会夏天户外庭院身高175cm体型偏瘦肤色偏白有什么搭配建议吗
</view>
<view class="aiTag" v-if="aiName==='膳食管家'" @click="sendMessageCeshi(2)">
我想开始减脂能为我设计一份适合上班族操作简单营养均衡的晚餐食谱吗
</view>
</view>
<view class="chat-input">
<view class="" style="flex: 1;">
<input class="input-field" placeholder="输入消息..." v-model="inputMsg" @confirm="sendMessage"
confirm-type="send" />
</view>
<view class="" style="width: 100px;">
<u-button type="primary" :disabled="!inputMsg.trim()||isAnswering" @click="sendMessage"
shape="circle">
发送
</u-button>
</view>
</view>
</view>
</view>
</template>
<script>
import {
WS_BASE_URL,
IMAGE_BASE_URL
IMAGE_BASE_URL
} from '@/utils/config';
export default {
@ -124,7 +139,14 @@
serviceUrl: '',
currentAnswer: '',
isAnswering: false,
isHandleClose:false
isHandleClose: false,
connectNum: 0,
aiName: '',
aiDefaultList: [
'最近雨季来了,家里总是很潮湿,有什么简单有效的除湿防霉小妙招吗?',
'我下周要参加一个商务休闲风格的客户午餐会夏天户外庭院身高175cm体型偏瘦肤色偏白有什么搭配建议吗',
'我想开始减脂,能为我设计一份适合上班族、操作简单、营养均衡的晚餐食谱吗?'
]
}
},
@ -132,11 +154,11 @@
this.serviceUrl = options.serviceUrl || '';
this.apiKey = options.apiKey || '';
this.botAvatar = options.icon || this.botAvatar;
this.aiName = options.name
const userInfo = wx.getStorageSync('userInfo') || {};
this.userId = userInfo.id || Date.now().toString();
this.userName = userInfo.name || '默认用户';
this.userAvatar = userInfo.avatar?`${IMAGE_BASE_URL+userInfo.avatar}`:this.userAvatar;
this.userAvatar = userInfo.avatar ? `${IMAGE_BASE_URL+userInfo.avatar}` : this.userAvatar;
uni.setNavigationBarTitle({
title: options.name || 'AI助手'
@ -153,7 +175,7 @@
// WebSocket
initWebSocket() {
if (this.isConnected) return;
console.log(WS_BASE_URL,'aiName===');
// 使 wx.connectSocket
this.socketTask = wx.connectSocket({
url: `${WS_BASE_URL}/api/v1/ws/ai?apiUrl=${encodeURIComponent(this.serviceUrl)}&apiToken=${this.apiKey}&userName=${this.userName}`,
@ -170,17 +192,20 @@
this.socketTask.onOpen(() => {
console.log('WebSocket连接已打开');
this.isConnected = true;
this.reconnectAttempts = 0;
const params = {
sender: 'bot',
thinkContent: '',
answerContent: '',
type: 'normal',
isTyping: false,
showAnswer: '已连接,请输入您的问题',
answerType: 2
// this.reconnectAttempts = 0;
if (this.reconnectAttempts === 0) {
const params = {
sender: 'bot',
thinkContent: '',
answerContent: '',
type: 'normal',
isTyping: false,
showAnswer: '已连接,请输入您的问题',
answerType: 2
}
this.addMessage(params);
}
this.addMessage(params);
});
this.socketTask.onMessage((res) => {
@ -207,7 +232,7 @@
this.socketTask.onClose(() => {
console.log('WebSocket连接已关闭');
this.isConnected = false;
if(!this.isHandleClose){
if (!this.isHandleClose) {
this.handleReconnect();
}
});
@ -329,7 +354,9 @@
if (lastMsg.answerContent.includes('outfit')) {
const ls = lastMsg.answerContent.replace(/\n/g, '')
try {
console.log(lastMsg.answerContent)
const obj = JSON.parse(lastMsg.answerContent)
console.log(obj)
lastMsg.answerContent = obj
} catch (error) {
lastMsg.answerContent = '哎呀AI开小差了请重新提问'
@ -437,7 +464,54 @@
this.inputMsg = '';
},
sendMessageCeshi(index) {
const content = this.aiDefaultList[index];
if (!content || !this.isConnected) return;
const params = {
sender: 'me',
thinkContent: '',
answerContent: '',
type: 'normal',
isTyping: false,
showAnswer: content,
answerType: 2
}
this.addMessage(params);
this.isAnswering = true
// 使 socketTask.send
this.socketTask.send({
data: content,
success: () => {
console.log('消息发送成功');
const params = {
sender: 'bot',
thinkContent: '思考中...',
answerContent: '',
type: 'normal',
isTyping: true,
showAnswer: '',
answerType: 2
}
//
this.addMessage(params);
},
fail: (err) => {
console.error('消息发送失败', err);
const params = {
sender: 'bot',
thinkContent: '',
answerContent: '',
type: 'normal',
isTyping: true,
showAnswer: '消息发送失败,请重试',
answerType: 2
}
this.addMessage(params);
}
});
this.inputMsg = '';
},
//
handleReconnect() {
if (this.reconnectAttempts >= this.maxReconnectAttempts) {
@ -466,14 +540,14 @@
// WebSocket
closeWebSocket() {
if (this.socketTask) {
//
this.socketTask.onClose = null;
this.socketTask.onError = null;
this.socketTask.onMessage = null;
this.socketTask.close();
this.socketTask = null;
this.isHandleClose=true
}
//
this.socketTask.onClose = null;
this.socketTask.onError = null;
this.socketTask.onMessage = null;
this.socketTask.close();
this.socketTask = null;
this.isHandleClose = true
}
this.isConnected = false;
},
@ -519,6 +593,14 @@
justify-content: flex-start;
}
.aiTag {
padding: 5px;
font-size: 14px;
background: #f0f0f0;
border-radius: 10px;
color: #666;
}
.avatar {
width: 36px;
height: 36px;
@ -544,13 +626,19 @@
color: #333333;
}
.chat-input {
display: flex;
padding: 10px;
.chat-bottom {
background-color: white;
border-top: 1px solid #ddd;
}
.chat-input {
background-color: white;
border-top: 1px solid #ddd;
display: flex;
padding: 10px;
}
.input-field {
flex: 1;
padding: 8px 15px;

View File

@ -50,6 +50,7 @@
},
methods: {
goAiType(item) {
console.log(item);
navigateTo({
url: `/pages/chat/chatPage?serviceUrl=${item.serviceUrl}&apiKey=${item.apiKey}&id=${item.id}&name=${item.name}&icon=${item.icon}`
});

View File

@ -1,5 +1,6 @@
<template>
<view class="doc-page">
<view class="doc-content">
<view class="doc-file" v-for="item of docList" @click="downLoadFile(item)">
<image src="/static/imgs/word.png" alt="" srcset="" class="doc-img"/>
@ -37,6 +38,12 @@
]
},
methods:{
handleBack() {
//
uni.redirectTo({
url: `/pages/meetingList/index`
})
},
async downLoadFile(fileUrl){
const result = await downloadPdfFiles(fileUrl);
if(result.success==true){
@ -46,7 +53,7 @@
}
},
reback(){
uni.redirectTo({
uni.reLaunch({
url: `/pages/meetingList/index`
})
}
@ -84,4 +91,25 @@
text-overflow: ellipsis;
white-space: nowrap;
}
.nav-bar {
display: flex;
align-items: center;
padding: 15px;
// background-color: #fff;
border-bottom: 1px solid #f5f5f5;
margin-top: 84rpx;
}
.nav-left {
display: flex;
align-items: center;
margin-right: 10px;
}
.nav-title {
flex: 1;
text-align: center;
// font-weight: bold;
width: 100%;
}
</style>

View File

@ -620,7 +620,7 @@
icon: 'success'
});
if (res.success == true) {
uni.navigateTo({
uni.redirectTo({
url: `/pages/docList/index?files=${JSON.stringify(res.data)}&&isSelfStudy=${this.isSelfStudy}`
})
}

View File

@ -1,13 +1,13 @@
<template>
<view class="container">
<!-- 自定义导航栏 -->
<view class="nav-bar">
<!-- <view class="nav-bar">
<view class="nav-left" @click="handleBack">
<u-icon name="arrow-left" size="44"></u-icon>
<!-- <text>返回</text> -->
<text>返回</text>
</view>
<text class="nav-title">近山社区</text>
</view>
</view> -->
<view v-if="tabsReady">
<u-tabs :list="tabList" :current="currentTab" @change="handleTabChange" border="false"
@ -397,13 +397,13 @@
padding: 15px;
// background-color: #fff;
border-bottom: 1px solid #f5f5f5;
margin-top: 84rpx;
padding-top: 60rpx;
}
.nav-left {
display: flex;
align-items: center;
margin-right: 10px;
// margin-right: 10px;
}
.nav-title {

View File

@ -93,6 +93,7 @@
uni.getLocation({
type: 'wgs84',
success: (res) => {
console.log('=====>',res)
resolve({
longitude: res.longitude,
latitude: res.latitude

View File

@ -4,6 +4,13 @@
<!-- <view class="handRight">
<view class="handTitle">请签名</view>
</view> -->
<!-- <view class="nav-bar">
<view class="nav-left" @click="handleBack">
<u-icon name="arrow-left" size="44"></u-icon>
<text>返回</text>
</view>
<text class="nav-title">签名</text>
</view> -->
<view class="handCenter">
<canvas class="handWriting" :disable-scroll="true" @touchstart="uploadScaleStart"
@touchmove="uploadScaleMove" @touchend="uploadScaleEnd" canvas-id="handWriting"></canvas>
@ -26,8 +33,8 @@
<button @click="undo" class="undoBtn">撤销</button>
<button @click="readShow=true" class="subBtn">完成</button>
</view>
</view>
<pickerColor :isShow="showPickerColor" :bottom="0" @callback='getPickerColor' />
@ -39,11 +46,18 @@
</template>
<script>
import { post } from "../../utils/request";
import pickerColor from "./pickerColor.vue"
import {IMAGE_BASE_URL,BASE_URL} from '@/utils/config';
import {downloadPdfFiles} from '@/utils/download.js'
import instructionVue from '../../components/instruction.vue';
import {
post
} from "../../utils/request";
import pickerColor from "./pickerColor.vue"
import {
IMAGE_BASE_URL,
BASE_URL
} from '@/utils/config';
import {
downloadPdfFiles
} from '@/utils/download.js'
import instructionVue from '../../components/instruction.vue';
export default {
components: {
pickerColor,
@ -51,8 +65,8 @@ import pickerColor from "./pickerColor.vue"
},
data() {
return {
readShow:false,
hasReaded:true,
readShow: false,
hasReaded: true,
showPickerColor: false,
ctx: '',
canvasWidth: 0,
@ -74,8 +88,8 @@ import pickerColor from "./pickerColor.vue"
},
toDataURL: void 0,
requestAnimationFrame: void 0,
applyInfo:null,
isSelfStudy:true,
applyInfo: null,
isSelfStudy: true,
};
},
props: { //props
@ -109,14 +123,14 @@ import pickerColor from "./pickerColor.vue"
},
},
onLoad(option) {
this.isSelfStudy=option.isSelfStudy
this.isSelfStudy = option.isSelfStudy
// A
const app = getApp()
if(app.globalData.applyInfo){
this.applyInfo=app.globalData.applyInfo
}else{
if (app.globalData.applyInfo) {
this.applyInfo = app.globalData.applyInfo
} else {
uni.navigateTo({
url:'/pages/meetingList/index'
url: '/pages/meetingList/index'
})
}
this.ctx = uni.createCanvasContext("handWriting");
@ -130,12 +144,16 @@ import pickerColor from "./pickerColor.vue"
});
},
methods: {
readChange(flag){
this.hasReaded=flag
},
postApply(){
this.readShow=false
handleBack() {
//
uni.navigateBack()
},
readChange(flag) {
this.hasReaded = flag
},
postApply() {
this.readShow = false
// API
this.subCanvas()
},
@ -430,141 +448,145 @@ import pickerColor from "./pickerColor.vue"
//
//
subCanvas() {
if (this.isEmpty()) {
uni.showToast({
title: '没有任何绘制内容哦',
icon: 'none',
});
return;
}
uni.showLoading({
title: '正在生成图片...'
});
uni.canvasToTempFilePath({
canvasId: 'handWriting',
fileType: 'png',
quality: 1,
success: async (res) => {
uni.hideLoading();
// 1.
try {
// await this.saveToAlbum(res.tempFilePath);
// 2.
uni.showLoading({
title: '正在上传签名...'
});
const uploadRes = await this.uploadSignature(res.tempFilePath);
uni.hideLoading();
this.applyInfo.applySign=uploadRes
const response=await post('/api/v1/app_auth/metting-room/order/register', this.applyInfo)
console.log("===response", response)
if (!response || !response.success) {
throw new Error('会议室预定失败');
}
if(response.success==true){
uni.navigateTo({
url:`/pages/docList/index?files=${JSON.stringify(response.data)}&&isSelfStudy=${this.isSelfStudy}`
})
}
if (this.isEmpty()) {
uni.showToast({
title: '会议室预定成功!',
icon: 'success'
title: '没有任何绘制内容哦',
icon: 'none',
});
// const result = await downloadPdfFiles(response);
// console.log(':', result);
// if(result.success==true){
// uni.navigateTo({
// url: `/pages/meetingList/index`
// });
// }
// 3.
// this.$emit('upload-success', {
// tempFilePath: res.tempFilePath,
// serverPath: uploadRes //
// });
} catch (error) {
uni.hideLoading();
uni.showToast({
title: error.message || '上传失败',
icon: 'none'
});
}
},
fail: (err) => {
uni.hideLoading();
uni.showToast({
title: '生成图片失败',
icon: 'none'
});
console.error(err);
}
});
return;
}
uni.showLoading({
title: '正在生成图片...'
});
uni.canvasToTempFilePath({
canvasId: 'handWriting',
fileType: 'png',
quality: 1,
success: async (res) => {
uni.hideLoading();
// 1.
try {
// await this.saveToAlbum(res.tempFilePath);
// 2.
uni.showLoading({
title: '正在上传签名...'
});
const uploadRes = await this.uploadSignature(res.tempFilePath);
uni.hideLoading();
this.applyInfo.applySign = uploadRes
const response = await post('/api/v1/app_auth/metting-room/order/register', this
.applyInfo)
console.log("===response", response)
if (!response || !response.success) {
throw new Error('会议室预定失败');
}
if (response.success == true) {
uni.redirectTo({
url: `/pages/docList/index?files=${JSON.stringify(response.data)}&&isSelfStudy=${this.isSelfStudy}`
})
}
uni.showToast({
title: '会议室预定成功!',
icon: 'success'
});
// const result = await downloadPdfFiles(response);
// console.log(':', result);
// if(result.success==true){
// uni.navigateTo({
// url: `/pages/meetingList/index`
// });
// }
// 3.
// this.$emit('upload-success', {
// tempFilePath: res.tempFilePath,
// serverPath: uploadRes //
// });
} catch (error) {
uni.hideLoading();
uni.showToast({
title: error.message || '上传失败',
icon: 'none'
});
}
},
fail: (err) => {
uni.hideLoading();
uni.showToast({
title: '生成图片失败',
icon: 'none'
});
console.error(err);
}
});
},
//
saveToAlbum(tempFilePath) {
return new Promise((resolve, reject) => {
uni.saveImageToPhotosAlbum({
filePath: tempFilePath,
success: () => {
uni.showToast({
title: '已保存到相册',
duration: 2000
});
resolve();
},
fail: (err) => {
reject(new Error('保存到相册失败'));
console.error(err);
}
});
});
return new Promise((resolve, reject) => {
uni.saveImageToPhotosAlbum({
filePath: tempFilePath,
success: () => {
uni.showToast({
title: '已保存到相册',
duration: 2000
});
resolve();
},
fail: (err) => {
reject(new Error('保存到相册失败'));
console.error(err);
}
});
});
},
//
uploadSignature(tempFilePath) {
return new Promise((resolve, reject) => {
//
const uploadUrl = IMAGE_BASE_URL+'/api/v1/upload';
uni.uploadFile({
url: uploadUrl,
filePath: tempFilePath,
name: 'file',
// formData: {
// //
// userId: '123', // ID
// type: 'signature'
// },
success: (uploadRes) => {
console.log(uploadRes);
console.log(JSON.parse(uploadRes.data))
try {
const {success,data} = JSON.parse(uploadRes.data);
if (success) {
resolve(data); // URL
} else {
reject(new Error(success || '上传失败'));
}
} catch (e) {
reject(new Error('解析服务器响应失败'));
}
},
fail: (err) => {
reject(new Error('上传请求失败'));
console.error(err);
}
});
});
return new Promise((resolve, reject) => {
//
const uploadUrl = IMAGE_BASE_URL + '/api/v1/upload';
uni.uploadFile({
url: uploadUrl,
filePath: tempFilePath,
name: 'file',
// formData: {
// //
// userId: '123', // ID
// type: 'signature'
// },
success: (uploadRes) => {
console.log(uploadRes);
console.log(JSON.parse(uploadRes.data))
try {
const {
success,
data
} = JSON.parse(uploadRes.data);
if (success) {
resolve(data); // URL
} else {
reject(new Error(success || '上传失败'));
}
} catch (e) {
reject(new Error('解析服务器响应失败'));
}
},
fail: (err) => {
reject(new Error('上传请求失败'));
console.error(err);
}
});
});
},
//
saveCanvasAsImg() {
@ -616,11 +638,31 @@ import pickerColor from "./pickerColor.vue"
overflow: hidden;
display: flex;
align-content: center;
flex-direction:column;
flex-direction: column;
/* justify-content: center; */
font-size: 28rpx;
}
.nav-bar {
display: flex;
align-items: center;
padding: 15px;
// background-color: #fff;
border-bottom: 1px solid #f5f5f5;
padding-top: 60rpx;
}
.nav-left {
display: flex;
align-items: center;
/* margin-right: 10px; */
}
.nav-title {
flex: 1;
text-align: center;
// font-weight: bold;
width: 100%;
}
.handWriting {
background: #fff;
width: 95vw;
@ -657,7 +699,7 @@ import pickerColor from "./pickerColor.vue"
display: flex;
/* flex-direction: column; */
justify-content: space-between;
align-content:center;
align-content: center;
align-items: center;
/* flex: 1; */
}

BIN
static/imgs/wechat.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.6 KiB

View File

@ -3,6 +3,7 @@
export const BASE_URL = 'https://jinshan.nantong.info';
export const IMAGE_BASE_URL = `https://jinshan.nantong.info`;
export const WS_BASE_URL = `wss://jinshan.nantong.info`;
// export const WS_BASE_URL = 'ws://10.10.1.6:8071';
// http://36.212.197.253:8071