Compare commits
29 Commits
8611ec4dc3
...
merge/tmp-
| Author | SHA1 | Date | |
|---|---|---|---|
| 50908a274b | |||
| 9e68562de5 | |||
| 8e5561c2a7 | |||
| 8d5c543a4f | |||
| cf411407dd | |||
| 86e4be302b | |||
| 2fd06796e1 | |||
| 60c51e551a | |||
| d0d3ac47c6 | |||
| af677f6565 | |||
| f889efeb16 | |||
| d026bb6180 | |||
| 82b856f5d9 | |||
| 7f33b6948a | |||
| 3489b89a0b | |||
| dc4f2769f9 | |||
| 5cf87e4d56 | |||
| c9ca63cff5 | |||
| a6072f4895 | |||
| 38947ddc62 | |||
| cfe83ada38 | |||
| 1e9e0ffea8 | |||
| 28acdfb621 | |||
| ad9f1c495b | |||
| 7c2a7468e7 | |||
| b2051dcf92 | |||
| e3c86de84a | |||
| 6e0eb5d4f3 | |||
| 9d186ff094 |
@@ -41,13 +41,17 @@ const localDevConfig = ({
|
||||
'local-2': { // 测试平台
|
||||
uniacid: 2,
|
||||
domain: 'http://localhost:8050/',
|
||||
},
|
||||
'2847': { // 家居装饰品
|
||||
uniacid: 2847,
|
||||
domain: 'https://xcx6.aigc-quickapp.com/',
|
||||
},
|
||||
'100': {
|
||||
uniacid: 100,
|
||||
domain: 'https://5g.aigc-quickapp.com/',
|
||||
},
|
||||
'1': { // 开发平台
|
||||
uniacid: 1,
|
||||
'1': {
|
||||
uniacid: 1,
|
||||
domain: 'https://5g.aigc-quickapp.com/',
|
||||
},
|
||||
'115': {
|
||||
uniacid: 115,
|
||||
domain: 'https://5g.aigc-quickapp.com/',
|
||||
},
|
||||
})['1']; // 选择要使用的环境配置
|
||||
|
||||
@@ -5,6 +5,17 @@ import store from '@/store/index.js'
|
||||
let currentConversationId = null;
|
||||
const CONVERSATION_KEY = 'ai_conversation_id';
|
||||
|
||||
/**
|
||||
* 获取域名配置参数(避免重复代码)
|
||||
*/
|
||||
function getDomainParams() {
|
||||
return {
|
||||
imgDomain: Config.imgDomain,
|
||||
h5Domain: Config.h5Domain,
|
||||
baseUrl: Config.baseUrl
|
||||
};
|
||||
}
|
||||
|
||||
// 初始化时从本地读取会话ID
|
||||
try {
|
||||
const saved = uni.getStorageSync(CONVERSATION_KEY);
|
||||
@@ -16,12 +27,28 @@ try {
|
||||
}
|
||||
|
||||
export default {
|
||||
/**
|
||||
* 获取uniacid
|
||||
* @returns {number} uniacid
|
||||
*/
|
||||
getUniacid() {
|
||||
return uni.getStorageSync('uniacid') || Config.uniacid; // 从缓存中获取uniacid,或使用默认uniacid
|
||||
},
|
||||
|
||||
/**
|
||||
* 发送普通消息(blocking 模式)
|
||||
*/
|
||||
async sendMessage(message, options = {}) {
|
||||
try {
|
||||
// 调试:打印关键状态
|
||||
console.log('[AI Service] sendMessage 开始执行');
|
||||
console.log('[AI Service] store.state.memberInfo:', store.state.memberInfo);
|
||||
console.log('[AI Service] uniacid:', this.getUniacid());
|
||||
console.log('[AI Service] currentConversationId:', this.getConversationId());
|
||||
|
||||
const aiConfig = store.getters.globalAIKefuConfig;
|
||||
console.log('[AI Service] aiConfig:', aiConfig);
|
||||
|
||||
const params = {
|
||||
url: '/api/kefu/chat',
|
||||
data: {
|
||||
@@ -31,28 +58,38 @@ export default {
|
||||
query: message,
|
||||
response_mode: 'blocking', // 强制 blocking
|
||||
user: store.state.memberInfo?.id || 'anonymous',
|
||||
conversation_id: this.getConversationId() || ''
|
||||
conversation_id: this.getConversationId() || '',
|
||||
...getDomainParams()
|
||||
},
|
||||
header: {
|
||||
'Content-Type': 'application/json'
|
||||
}
|
||||
};
|
||||
|
||||
console.log('Sending blocking request to:', params.url);
|
||||
console.log('Request data:', params.data);
|
||||
console.log('[AI Service] 发送请求到:', params.url);
|
||||
console.log('[AI Service] 请求参数:', JSON.stringify(params.data, null, 2));
|
||||
|
||||
const response = await http.sendRequest({
|
||||
...params,
|
||||
async: false
|
||||
});
|
||||
|
||||
console.log('[AI Service] 收到响应:', response);
|
||||
|
||||
const result = this.handleResponse(response);
|
||||
if (result.conversationId) {
|
||||
this.setConversationId(result.conversationId);
|
||||
}
|
||||
return result;
|
||||
} catch (error) {
|
||||
console.error('Dify API请求失败:', error);
|
||||
console.error('[AI Service] Dify API请求失败,详细错误:', error);
|
||||
console.error('[AI Service] 错误堆栈:', error.stack);
|
||||
// 打印更多信息帮助调试
|
||||
console.error('[AI Service] store 状态:', {
|
||||
memberInfo: store.state.memberInfo,
|
||||
uniacid: this.getUniacid(),
|
||||
token: store.state.token
|
||||
});
|
||||
throw new Error('AI服务暂时不可用,请稍后重试');
|
||||
}
|
||||
},
|
||||
@@ -81,7 +118,7 @@ export default {
|
||||
socketTask.send({
|
||||
data: JSON.stringify({
|
||||
action: 'auth',
|
||||
uniacid: store.state.uniacid || '1',
|
||||
uniacid: this.getUniacid(),
|
||||
token: store.state.token || 'test_token',
|
||||
user_id: store.state.memberInfo?.id || 'anonymous'
|
||||
})
|
||||
@@ -99,10 +136,11 @@ export default {
|
||||
socketTask.send({
|
||||
data: JSON.stringify({
|
||||
action: 'chat',
|
||||
uniacid: store.state.uniacid || '1',
|
||||
uniacid: this.getUniacid(),
|
||||
query: message,
|
||||
user_id: store.state.memberInfo?.id || 'anonymous',
|
||||
conversation_id: this.getConversationId() || ''
|
||||
conversation_id: this.getConversationId() || '',
|
||||
...getDomainParams()
|
||||
})
|
||||
});
|
||||
} else if (data.type === 'auth_failed') {
|
||||
@@ -179,12 +217,14 @@ export default {
|
||||
'Accept': 'text/event-stream',
|
||||
},
|
||||
body: JSON.stringify({
|
||||
uniacid: store.state.uniacid || '1',
|
||||
uniacid: this.getUniacid(),
|
||||
token: store.state.token || 'test_token',
|
||||
inputs: {},
|
||||
query: message,
|
||||
response_mode: 'streaming',
|
||||
user_id: store.state.memberInfo?.id || 'anonymous',
|
||||
conversation_id: this.getConversationId() || ''
|
||||
conversation_id: this.getConversationId() || '',
|
||||
...getDomainParams()
|
||||
})
|
||||
});
|
||||
|
||||
@@ -318,17 +358,19 @@ export default {
|
||||
* 生成新会话(如需)
|
||||
*/
|
||||
async generateConversationId() {
|
||||
const params = {
|
||||
url: '/api/kefu/createConversation',
|
||||
data: {
|
||||
uniacid: store.state.uniacid,
|
||||
user_id: store.state.memberInfo?.id || 'anonymous',
|
||||
member_id: store.state.memberInfo?.id || '',
|
||||
},
|
||||
header: {
|
||||
'Content-Type': 'application/json'
|
||||
}
|
||||
};
|
||||
const params = {
|
||||
url: '/api/kefu/createConversation',
|
||||
data: {
|
||||
uniacid: this.getUniacid(),
|
||||
token: store.state.token || 'test_token',
|
||||
user_id: store.state.memberInfo?.id || 'anonymous',
|
||||
member_id: store.state.memberInfo?.id || '',
|
||||
...getDomainParams()
|
||||
},
|
||||
header: {
|
||||
'Content-Type': 'application/json'
|
||||
}
|
||||
};
|
||||
const response = await http.sendRequest({
|
||||
...params,
|
||||
async: false
|
||||
@@ -346,6 +388,7 @@ export default {
|
||||
async: false,
|
||||
data: {}
|
||||
});
|
||||
console.log('/api/kefu/health response', response);
|
||||
const available = [response?.data?.status, response?.data?.components?.ai_service_config?.status]
|
||||
.filter(item => item === 'healthy').length > 0;
|
||||
return {
|
||||
@@ -367,7 +410,10 @@ export default {
|
||||
try {
|
||||
const response = await http.sendRequest({
|
||||
url: '/api/kefu/clear-conversation',
|
||||
data: { conversation_id: conversationId },
|
||||
data: {
|
||||
conversation_id: conversationId,
|
||||
...getDomainParams()
|
||||
},
|
||||
async: false
|
||||
});
|
||||
return response.success;
|
||||
@@ -386,13 +432,14 @@ export default {
|
||||
throw new Error('会话ID(conversation_id)是必填参数');
|
||||
}
|
||||
const requestData = {
|
||||
uniacid: params.uniacid || store.state.uniacid || '1',
|
||||
uniacid: params.uniacid || this.getUniacid(),
|
||||
conversation_id: params.conversation_id,
|
||||
user_id: params.user_id || store.state.memberInfo?.id || 'anonymous',
|
||||
limit: params.limit || 20,
|
||||
offset: params.offset || 0,
|
||||
member_id: params.member_id || store.state.memberInfo?.id || '',
|
||||
token: params.token || ''
|
||||
token: params.token || '',
|
||||
...getDomainParams()
|
||||
};
|
||||
const response = await http.sendRequest({
|
||||
url: '/api/kefu/getHistory',
|
||||
@@ -431,13 +478,15 @@ export default {
|
||||
if (window.currentEventSource) {
|
||||
window.currentEventSource.close();
|
||||
}
|
||||
const params = new URLSearchParams({
|
||||
uniacid: store.state.uniacid || '1',
|
||||
user_id: store.state.memberInfo?.id || '123456',
|
||||
const paramsObj = {
|
||||
uniacid: this.getUniacid(),
|
||||
user_id: store.state.memberInfo?.id,
|
||||
query: message,
|
||||
conversation_id: conversationId || '',
|
||||
stream: 'true'
|
||||
});
|
||||
stream: 'true',
|
||||
...getDomainParams()
|
||||
};
|
||||
const params = new URLSearchParams(paramsObj);
|
||||
const url = `${Config.baseUrl}/api/kefu/chat?${params.toString()}`;
|
||||
try {
|
||||
const eventSource = new EventSource(url);
|
||||
|
||||
@@ -99,9 +99,6 @@
|
||||
<text class="unit price-style small">.{{
|
||||
parseFloat(showPrice(item)).toFixed(2).split('.')[1] }}</text>
|
||||
</block>
|
||||
<block v-else>
|
||||
<text class="unit price-style small">{{ $lang('Make') ? $lang('Make') : '询底价' }}</text>
|
||||
</block>
|
||||
</view>
|
||||
<view class="member-price-tag"
|
||||
v-if="item.member_price && item.member_price == showPrice(item)">
|
||||
@@ -120,6 +117,11 @@
|
||||
<text>{{ showMarketPrice(item) }}</text>
|
||||
</view>
|
||||
</view>
|
||||
<view class="ai-chat-btn-wrap" v-if="item.isinformation == 1">
|
||||
<view class="ai-chat-btn" @tap.stop="sendToAIChat(item)">
|
||||
立即咨询
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- <view class="right-wrap" v-if="value.template == 2 || value.template == 4">
|
||||
<block v-if="item.is_virtual">
|
||||
@@ -185,18 +187,14 @@
|
||||
</view>
|
||||
<view class="price-wrap">
|
||||
<view class="discount-price">
|
||||
<block v-if="item.isinformation == 0">
|
||||
<text class="unit price-style small">¥</text>
|
||||
<text class="price price-style large">{{
|
||||
parseFloat(showPrice(item)).toFixed(2).split('.')[0] }}</text>
|
||||
<text class="unit price-style small">.{{
|
||||
parseFloat(showPrice(item)).toFixed(2).split('.')[1] }}</text>
|
||||
</block>
|
||||
<block v-else>
|
||||
<text class="unit price-style small">{{ $lang('Make') ? $lang('Make') : '询底价' }}</text>
|
||||
</block>
|
||||
|
||||
</view>
|
||||
<block v-if="item.isinformation == 0">
|
||||
<text class="unit price-style small">¥</text>
|
||||
<text class="price price-style large">{{
|
||||
parseFloat(showPrice(item)).toFixed(2).split('.')[0] }}</text>
|
||||
<text class="unit price-style small">.{{
|
||||
parseFloat(showPrice(item)).toFixed(2).split('.')[1] }}</text>
|
||||
</block>
|
||||
</view>
|
||||
<view class="member-price-tag"
|
||||
v-if="item.member_price && item.member_price == showPrice(item)">
|
||||
<image :src="$util.img('public/uniapp/index/VIP.png')" mode="widthFix" />
|
||||
@@ -213,6 +211,11 @@
|
||||
<text>{{ showMarketPrice(item) }}</text>
|
||||
</view>
|
||||
</view>
|
||||
<view class="ai-chat-btn-wrap" v-if="item.isinformation == 1">
|
||||
<view class="ai-chat-btn" @tap.stop="sendToAIChat(item)">
|
||||
立即咨询
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class="right-wrap" v-if="value.template == 2">
|
||||
<block v-if="item.is_virtual">
|
||||
@@ -721,23 +724,13 @@ export default {
|
||||
}
|
||||
},
|
||||
/**
|
||||
* 发送商品信息到智能客服
|
||||
* 跳转到商品详情
|
||||
* @param {Object} item 商品信息
|
||||
*/
|
||||
sendToAIChat(item) {
|
||||
const productInfo = {
|
||||
goods_id: item.goods_id,
|
||||
goods_name: item.goods_name,
|
||||
price: this.showPrice(item),
|
||||
image: this.goodsImg(item.goods_image),
|
||||
category_id: item.category_id
|
||||
}
|
||||
|
||||
uni.setStorageSync('selectedProduct', productInfo)
|
||||
|
||||
uni.navigateTo({
|
||||
url: '/pages_tool/ai-chat/index'
|
||||
})
|
||||
this.$util.redirectTo('/pages_goods/detail', {
|
||||
goods_id: item.goods_id
|
||||
});
|
||||
},
|
||||
diyRedirectTo(link) {
|
||||
if (!link) return;
|
||||
@@ -1406,5 +1399,24 @@ export default {
|
||||
}
|
||||
}
|
||||
|
||||
.ai-chat-btn-wrap {
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
margin-top: auto;
|
||||
padding-top: 10rpx;
|
||||
}
|
||||
|
||||
.ai-chat-btn {
|
||||
background-color: #ff0000;
|
||||
color: #fff;
|
||||
padding: 12rpx 30rpx;
|
||||
border-radius: 40rpx;
|
||||
font-size: 26rpx;
|
||||
font-weight: 500;
|
||||
line-height: 1.2;
|
||||
text-align: center;
|
||||
white-space: nowrap;
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
</style>
|
||||
@@ -913,7 +913,7 @@ export default {
|
||||
// ===== 主容器样式 =====
|
||||
.tab-diy-component-preview-container {
|
||||
width: 100%;
|
||||
min-height: 300px;
|
||||
min-height: 0px;
|
||||
display: flex;
|
||||
border: 1px solid #e0e0e0;
|
||||
border-radius: 4px;
|
||||
|
||||
@@ -53,8 +53,15 @@ export default {
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
this.listenPrivacySettingChange()
|
||||
this.curPageShow()
|
||||
// 检查配置,决定是否显示隐私协议
|
||||
const shopInfo = uni.getStorageSync('shopInfo');
|
||||
if (shopInfo?.ischina == 1 && shopInfo?.index_login_auth == 1) {
|
||||
this.listenPrivacySettingChange()
|
||||
this.curPageShow()
|
||||
} else {
|
||||
// 如果不需要显示隐私协议,直接触发同意事件
|
||||
this.$emit('agree');
|
||||
}
|
||||
},
|
||||
created() {
|
||||
try {
|
||||
@@ -152,6 +159,14 @@ export default {
|
||||
},
|
||||
// 主动查询用户隐私政策授权状态
|
||||
proactive() {
|
||||
// 检查配置,决定是否显示隐私协议
|
||||
const shopInfo = uni.getStorageSync('shopInfo');
|
||||
if (!(shopInfo?.ischina == 1 && shopInfo?.index_login_auth == 1)) {
|
||||
// 如果不需要显示隐私协议,直接触发同意事件
|
||||
this.$emit('agree');
|
||||
return;
|
||||
}
|
||||
|
||||
// #ifdef MP-WEIXIN
|
||||
if (wx.getPrivacySetting) {
|
||||
wx.getPrivacySetting({
|
||||
|
||||
@@ -3,5 +3,5 @@ export const lang = {
|
||||
title: '商品分类',
|
||||
search:'商品搜索',
|
||||
seeMore : '查看更多',
|
||||
Make: "询底价"
|
||||
Make: "立即咨询"
|
||||
}
|
||||
|
||||
@@ -2,7 +2,7 @@ export const lang = {
|
||||
//title为每个页面的标题
|
||||
title: '',
|
||||
select: '选择',
|
||||
details:'资源详情',
|
||||
details:'商品详情',
|
||||
params: '参数',
|
||||
service: '商品服务',
|
||||
allGoods: '全部商品',
|
||||
@@ -11,7 +11,7 @@ export const lang = {
|
||||
home:'首页',
|
||||
cart:'购物车',
|
||||
leave:'立即留言',
|
||||
make:'联系我们',
|
||||
make:'立即咨询',
|
||||
|
||||
send:'配送',
|
||||
express:'快递发货',
|
||||
@@ -22,7 +22,7 @@ export const lang = {
|
||||
status:'该商品已下架',
|
||||
sellout:'库存不足',
|
||||
max:'已达最大限购数量',
|
||||
makebtn:'价格电议',
|
||||
makebtn:'立即咨询',
|
||||
sales:'销量',
|
||||
stock:'库存',
|
||||
kefu:'客服',
|
||||
|
||||
@@ -6,6 +6,6 @@ export const lang = {
|
||||
Price:'价格',
|
||||
Filter:'筛选',
|
||||
Search:'请输入您要搜索的商品',
|
||||
Make:'立即询底价',
|
||||
Make:'立即咨询',
|
||||
|
||||
}
|
||||
|
||||
@@ -43,7 +43,7 @@
|
||||
{
|
||||
"path": "detail",
|
||||
"style": {
|
||||
"navigationBarTitleText": "资源详情"
|
||||
"navigationBarTitleText": "商品详情"
|
||||
}
|
||||
},
|
||||
{
|
||||
|
||||
@@ -3,7 +3,8 @@ export default {
|
||||
return {
|
||||
minScrollTop: 100, // 设置回到顶端按钮显示要求,最小页面滚动距离
|
||||
wechatQrcode: '', // 公众号二维码
|
||||
diyRoute: '/pages/index/index'
|
||||
diyRoute: '/pages/index/index',
|
||||
shopInfo: null // 店铺信息
|
||||
};
|
||||
},
|
||||
onLoad(option) {
|
||||
@@ -15,10 +16,15 @@ export default {
|
||||
// #endif
|
||||
this.name = option.name || 'DIY_VIEW_INDEX'; // 根据店铺运营模式,打开平台(shop)或者连锁门店(stroe)页面,接口会自行判断
|
||||
|
||||
// 获取店铺信息
|
||||
this.shopInfo = uni.getStorageSync('shopInfo');
|
||||
},
|
||||
onShow() {
|
||||
// 获取关注公众号二维码
|
||||
this.getFollowQrcode();
|
||||
|
||||
// 重新获取店铺信息
|
||||
this.shopInfo = uni.getStorageSync('shopInfo');
|
||||
},
|
||||
mounted() {
|
||||
// 监听图片、文字、商品列表等组件的点击事件
|
||||
@@ -59,6 +65,11 @@ export default {
|
||||
officialAccountsClose() {
|
||||
this.$refs.officialAccountsPopup.close();
|
||||
},
|
||||
// 判断是否需要登录授权
|
||||
_needLoginAuth() {
|
||||
// 检查 index_login_auth 都开启时才需要登录授权
|
||||
return this.shopInfo?.index_login_auth == 1;
|
||||
},
|
||||
// 统一处理点击及触摸事件
|
||||
_handleDiyGroupInteractionEvent(payload) {
|
||||
// #ifdef H5
|
||||
@@ -66,6 +77,11 @@ export default {
|
||||
return true;
|
||||
// #endif
|
||||
|
||||
// 如果不需要登录授权,直接返回 true 继续传播
|
||||
if (!this._needLoginAuth()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// 如果已登录,直接返回 true 继续传播
|
||||
if (this.storeToken) {
|
||||
return true;
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
<view scroll-y="true" class="goods-detail" :class="isIphoneX ? 'active' : ''">
|
||||
<view class="goods-container">
|
||||
<!-- AI客服悬浮按钮 -->
|
||||
<view class="ai-chat-float-btn" @tap.stop="$emit('aiChatClick')" v-if="goodsSkuDetail">
|
||||
<view class="ai-chat-float-btn" @tap.stop="$emit('aiChatClick')" v-if="showAIChatBtn">
|
||||
<image :src="aiAvatarUrl" mode="aspectFill" class="ai-avatar-icon" />
|
||||
</view>
|
||||
|
||||
@@ -464,6 +464,7 @@
|
||||
import scroll from '@/common/js/scroll-view.js';
|
||||
import detail from './detail.js';
|
||||
import IMAGE_CONFIG from '@/common/js/image-config.js';
|
||||
import { createCustomerService } from '@/common/js/customer-service.js';
|
||||
|
||||
import pengpaiFadeinOut from '../pengpai-fadein-out/pengpai-fadein-out.vue';
|
||||
|
||||
@@ -483,6 +484,10 @@ export default {
|
||||
computed: {
|
||||
aiAvatarUrl() {
|
||||
return this.$util.img(IMAGE_CONFIG.aiAvatar);
|
||||
},
|
||||
showAIChatBtn() {
|
||||
const customerService = createCustomerService(this);
|
||||
return customerService.hasValidKefuConfig() && customerService.isAIKefu();
|
||||
}
|
||||
},
|
||||
mixins: [scroll, detail]
|
||||
|
||||
@@ -26,7 +26,8 @@
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
diyData: null
|
||||
diyData: null,
|
||||
mpShareData: null //小程序分享数据
|
||||
};
|
||||
},
|
||||
onLoad() {
|
||||
@@ -38,6 +39,25 @@ export default {
|
||||
onShow() {
|
||||
this.$util.hideHomeButton();
|
||||
if (this.$refs.category) this.$refs.category[0].pageShow();
|
||||
|
||||
//小程序分享
|
||||
// #ifdef MP-WEIXIN
|
||||
this.$util.getMpShare('/pages_goods/category').then(res => {
|
||||
this.mpShareData = res;
|
||||
}).catch(err => {
|
||||
// 如果后台没配置,用默认值
|
||||
this.mpShareData = {
|
||||
appMessage: {
|
||||
title: '发现超多好物,快来看看',
|
||||
path: '/pages_goods/category'
|
||||
},
|
||||
timeLine: {
|
||||
title: '发现超多好物,快来看看',
|
||||
query: '/pages_goods/category'
|
||||
}
|
||||
};
|
||||
});
|
||||
// #endif
|
||||
},
|
||||
onUnload() {
|
||||
if (!this.storeToken && this.$refs.login) this.$refs.login.cancelCompleteInfo();
|
||||
@@ -69,6 +89,24 @@ export default {
|
||||
onPullDownRefresh() {
|
||||
uni.hideTabBar();
|
||||
this.getDiyInfo();
|
||||
},
|
||||
onShareAppMessage() {
|
||||
return this.mpShareData?.appMessage || {
|
||||
title: '发现超多好物,快来看看',
|
||||
path: '/pages_goods/category'
|
||||
};
|
||||
},
|
||||
onShareTimeline() {
|
||||
return this.mpShareData?.timeLine || {
|
||||
title: '发现超多好物,快来看看',
|
||||
query: '/pages_goods/category'
|
||||
};
|
||||
},
|
||||
onAddToFavorites() {
|
||||
return {
|
||||
title: '发现超多好物,快来看看',
|
||||
path: '/pages_goods/category'
|
||||
};
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
@@ -77,7 +77,6 @@
|
||||
</block>
|
||||
<block v-else>
|
||||
<template>
|
||||
<text class="price price-font" style="font-weight: 600;">{{$lang('makebtn')}}</text>
|
||||
</template>
|
||||
</block>
|
||||
</view>
|
||||
@@ -461,11 +460,12 @@
|
||||
<ns-goods-action-icon :text="$lang('follow')" :icon="whetherCollection == 1 ? 'icon-likefill color-base-text' : 'icon-guanzhu'" @click="editCollection" />
|
||||
<!-- #endif -->
|
||||
<block v-if="goodsSkuDetail.isinformation >= 1">
|
||||
|
||||
|
||||
<ns-goods-action-button v-if="goodsSkuDetail.isinformation == 1" class="goods-action-button active3" disabled-text="" backgroundColor="#54c952" @click="phoneClick(goodsSkuDetail.goods_mobile)" :text="$lang('make')" :disabled="false" />
|
||||
<ns-goods-action-button v-if="goodsSkuDetail.isinformation == 2" class="goods-action-button active3" disabled-text="" backgroundColor="#54c952" @click="showinformation" :text="$lang('leave')" :disabled="false" />
|
||||
<!-- <ns-goods-action-button v-if="goodsSkuDetail.isinformation == 2" class="goods-action-button active3" disabled-text="" backgroundColor="#54c952" @click="buyNow" text="商品留言" :disabled="false" /> -->
|
||||
|
||||
<ns-goods-action-button v-if="goodsSkuDetail.isinformation == 2" class="goods-action-button active3" disabled-text="" backgroundColor="#54c952" @click="showinformation" :text="$lang('leave')" :disabled="false" />
|
||||
<ns-goods-action-button v-if="goodsSkuDetail.isinformation == 3" class="goods-action-button active3" disabled-text="" backgroundColor="#54c952" @click="goToAIChat" text="智能客服" :disabled="false" />
|
||||
<!-- <ns-goods-action-button v-if="goodsSkuDetail.isinformation == 2" class="goods-action-button active3" disabled-text="" backgroundColor="#54c952" @click="buyNow" text="商品留言" :disabled="false" /> -->
|
||||
|
||||
</block>
|
||||
<block v-else>
|
||||
<block v-if="goodsSkuDetail.stock == 0 && !goodsSkuDetail.sku_spec_format">
|
||||
@@ -515,6 +515,19 @@
|
||||
|
||||
<!-- 隐私弹窗 -->
|
||||
<privacy-popup ref="privacyPopup"></privacy-popup>
|
||||
|
||||
<!-- 联系电话弹窗 -->
|
||||
<uni-popup ref="contactPopup" type="center">
|
||||
<view class="contact-popup">
|
||||
<view class="contact-content">
|
||||
<text class="contact-text">可在手机端拨打 021-51815181</text>
|
||||
</view>
|
||||
<view class="contact-buttons">
|
||||
<button class="contact-btn cancel-btn" @click="closeContactPopup">取消</button>
|
||||
<button class="contact-btn copy-btn" @click="copyPhoneNumber">复制到剪切板</button>
|
||||
</view>
|
||||
</view>
|
||||
</uni-popup>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
@@ -538,23 +551,54 @@ export default {
|
||||
* @param {Object} item 商品信息
|
||||
*/
|
||||
sendToAIChat(item) {
|
||||
this.$refs.contactPopup.open();
|
||||
},
|
||||
|
||||
/**
|
||||
* 跳转到智能客服页面
|
||||
*/
|
||||
goToAIChat() {
|
||||
const productInfo = {
|
||||
goods_id: item.goods_id || '',
|
||||
goods_name: item.goods_name || '',
|
||||
price: item.discount_price || item.member_price || item.price || '',
|
||||
image: item.sku_image || '',
|
||||
category_id: item.category_id || ''
|
||||
}
|
||||
goods_id: this.goodsSkuDetail.goods_id || '',
|
||||
goods_name: this.goodsSkuDetail.goods_name || '',
|
||||
price: this.goodsSkuDetail.discount_price || this.goodsSkuDetail.member_price || this.goodsSkuDetail.price || '',
|
||||
image: this.goodsSkuDetail.sku_image || '',
|
||||
category_id: this.goodsSkuDetail.category_id || ''
|
||||
};
|
||||
|
||||
uni.setStorageSync('selectedProduct', productInfo)
|
||||
uni.setStorageSync('selectedProduct', productInfo);
|
||||
|
||||
uni.navigateTo({
|
||||
url: '/pages_tool/ai-chat/index'
|
||||
})
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
* 关闭联系电话弹窗
|
||||
*/
|
||||
closeContactPopup() {
|
||||
this.$refs.contactPopup.close();
|
||||
},
|
||||
|
||||
/**
|
||||
* 复制电话号码到剪切板
|
||||
*/
|
||||
copyPhoneNumber() {
|
||||
uni.setClipboardData({
|
||||
data: '021-51815181',
|
||||
success: () => {
|
||||
uni.showToast({
|
||||
title: '复制成功',
|
||||
icon: 'success'
|
||||
});
|
||||
this.closeContactPopup();
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
@import '@/common/css/goods_detail.scss';
|
||||
@import './public/css/detail.scss';
|
||||
@@ -566,6 +610,57 @@ export default {
|
||||
z-index: 999;
|
||||
}
|
||||
|
||||
.contact-popup {
|
||||
width: 600rpx;
|
||||
background: #ffffff;
|
||||
border-radius: 16rpx;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.contact-content {
|
||||
padding: 60rpx 40rpx;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.contact-text {
|
||||
font-size: 32rpx;
|
||||
color: #333333;
|
||||
line-height: 1.5;
|
||||
}
|
||||
|
||||
.contact-buttons {
|
||||
display: flex;
|
||||
border-top: 1px solid #e5e5e5;
|
||||
}
|
||||
|
||||
.contact-btn {
|
||||
flex: 1;
|
||||
height: 90rpx;
|
||||
line-height: 90rpx;
|
||||
text-align: center;
|
||||
font-size: 32rpx;
|
||||
border: none;
|
||||
background: transparent;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
border-radius: 0;
|
||||
}
|
||||
|
||||
.contact-btn::after {
|
||||
border: none;
|
||||
}
|
||||
|
||||
.cancel-btn {
|
||||
color: #333333;
|
||||
background: #ffffff;
|
||||
border-right: 1px solid #e5e5e5;
|
||||
}
|
||||
|
||||
.copy-btn {
|
||||
color: #ffffff;
|
||||
background: #54c952;
|
||||
}
|
||||
|
||||
</style>
|
||||
<style scoped>
|
||||
::v-deep .action-icon-wrap .iconfont.icon-shouye1 {
|
||||
|
||||
@@ -75,9 +75,6 @@
|
||||
<text class="unit price-style small">.{{
|
||||
parseFloat(showPrice(item)).toFixed(2).split('.')[1] }}</text>
|
||||
</view>
|
||||
<view class="discount-price" v-else>
|
||||
<text class="price price-style large">{{ langstatus ? $lang('Make') : '询底价' }}</text>
|
||||
</view>
|
||||
</view>
|
||||
<view class="pro-info" v-if="item.isinformation == 0">
|
||||
<view class="block-wrap">
|
||||
@@ -92,6 +89,11 @@
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
<view class="ai-chat-btn-wrap" v-if="item.isinformation == 1">
|
||||
<view class="ai-chat-btn" @click.stop="sendToAIChat(item)">
|
||||
立即咨询
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
@@ -121,9 +123,6 @@
|
||||
<text class="unit price-style small">.{{
|
||||
parseFloat(showPrice(item)).toFixed(2).split('.')[1] }}</text>
|
||||
</view>
|
||||
<view class="discount-price" v-else>
|
||||
<text class="price price-style large">{{ langstatus ? $lang('Make') : '询底价' }}</text>
|
||||
</view>
|
||||
</view>
|
||||
<view class="pro-info" v-if="item.isinformation == 0">
|
||||
<view class="block-wrap">
|
||||
@@ -138,6 +137,11 @@
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
<view class="ai-chat-btn-wrap" v-if="item.isinformation == 1">
|
||||
<view class="ai-chat-btn" @click.stop="sendToAIChat(item)">
|
||||
立即咨询
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
@@ -219,7 +223,14 @@ export default {
|
||||
data() {
|
||||
return {};
|
||||
},
|
||||
mixins: [list]
|
||||
mixins: [list],
|
||||
methods: {
|
||||
sendToAIChat(item) {
|
||||
this.$util.redirectTo('/pages_goods/detail', {
|
||||
goods_id: item.goods_id
|
||||
});
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
@@ -235,4 +246,24 @@ export default {
|
||||
::v-deep .sku-layer .uni-popup__wrapper.uni-custom .uni-popup__wrapper-box {
|
||||
max-height: unset !important;
|
||||
}
|
||||
|
||||
.ai-chat-btn-wrap {
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
margin-top: auto;
|
||||
padding-top: 10rpx;
|
||||
}
|
||||
|
||||
.ai-chat-btn {
|
||||
background-color: #ff0000;
|
||||
color: #fff;
|
||||
padding: 12rpx 30rpx;
|
||||
border-radius: 40rpx;
|
||||
font-size: 26rpx;
|
||||
font-weight: 500;
|
||||
line-height: 1.2;
|
||||
text-align: center;
|
||||
white-space: nowrap;
|
||||
display: inline-block;
|
||||
}
|
||||
</style>
|
||||
@@ -88,7 +88,7 @@
|
||||
parseFloat(showPrice(item)).toFixed(2).split('.')[1] }}</text>
|
||||
</view>
|
||||
<view class="discount-price" v-else>
|
||||
<text class="price price-style large">{{ $lang('Make') ? $lang('Make') : '询底价'
|
||||
<text class="price price-style large">{{ $lang('Make') ? $lang('Make') : '立即咨询'
|
||||
}}</text>
|
||||
</view>
|
||||
|
||||
@@ -182,7 +182,7 @@
|
||||
parseFloat(showPrice(item)).toFixed(2).split('.')[1] }}</text>
|
||||
</view>
|
||||
<view class="discount-price" v-else>
|
||||
<text class="price price-style large">{{ $lang('Make') ? $lang('Make') : '询底价'
|
||||
<text class="price price-style large">{{ $lang('Make') ? $lang('Make') : '立即咨询'
|
||||
}}</text>
|
||||
</view>
|
||||
<view class="member-price-tag"
|
||||
|
||||
@@ -209,14 +209,25 @@
|
||||
:adjust-position="true"
|
||||
:cursor-spacing="150"
|
||||
@confirm="sendMessage"
|
||||
@input="onInput" />
|
||||
@input="onInput"
|
||||
@linechange="onLineChange" />
|
||||
|
||||
<!-- 扩大按钮 -->
|
||||
<button v-if="inputLineCount > 3" class="expand-btn" @click="openExpandEditor">
|
||||
<text class="iconfont icon-expand">[ ]</text>
|
||||
</button>
|
||||
|
||||
<!-- Emoji按钮 -->
|
||||
<button class="emoji-btn" @click="toggleEmojiPanel">
|
||||
<text class="iconfont icon-smile">😊</text>
|
||||
</button>
|
||||
|
||||
<!-- 发送按钮 -->
|
||||
<button
|
||||
class="send-btn"
|
||||
:class="{ disabled: !inputText.trim() }"
|
||||
:class="{ disabled: !canSendMessage }"
|
||||
@click="sendMessage"
|
||||
:disabled="!inputText.trim()">
|
||||
:disabled="!canSendMessage">
|
||||
<text>发送</text>
|
||||
</button>
|
||||
</view>
|
||||
@@ -261,6 +272,54 @@
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- Emoji面板 -->
|
||||
<view v-if="showEmojiPanel" class="emoji-popup">
|
||||
<view class="emoji-mask" @click="hideEmojiPanel"></view>
|
||||
<view class="emoji-panel">
|
||||
<view class="emoji-header">
|
||||
<text>表情</text>
|
||||
<button class="close-btn" @click="hideEmojiPanel">
|
||||
<text>×</text>
|
||||
</button>
|
||||
</view>
|
||||
<view class="emoji-grid">
|
||||
<view
|
||||
v-for="(emoji, index) in emojiList"
|
||||
:key="index"
|
||||
class="emoji-item"
|
||||
@click="insertEmoji(emoji)">
|
||||
<text class="emoji-text">{{ emoji }}</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 扩大编辑器弹窗 -->
|
||||
<view v-if="showExpandEditor" class="expand-editor-popup">
|
||||
<view class="expand-editor-mask" @click="closeExpandEditor"></view>
|
||||
<view class="expand-editor-panel">
|
||||
<view class="expand-editor-header">
|
||||
<text>编辑内容</text>
|
||||
<button class="close-btn" @click="closeExpandEditor">
|
||||
<text>×</text>
|
||||
</button>
|
||||
</view>
|
||||
<textarea
|
||||
v-model="expandInputText"
|
||||
class="expand-editor-input"
|
||||
placeholder="请输入您的问题..."
|
||||
:maxlength="500"
|
||||
:auto-height="true"
|
||||
:show-confirm-bar="false"
|
||||
:adjust-position="true"
|
||||
:focus="true" />
|
||||
<view class="expand-editor-footer">
|
||||
<button class="expand-cancel-btn" @click="closeExpandEditor">取消</button>
|
||||
<button class="expand-send-btn" @click="sendFromExpandEditor" :disabled="!expandInputText.trim()">发送</button>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 语音输入面板 -->
|
||||
<view v-if="enalbeVoicePanelShow" class="voice-popup">
|
||||
<view class="voice-mask" @click="hideVoicePanel"></view>
|
||||
@@ -411,6 +470,12 @@ export default {
|
||||
messageId: 0,
|
||||
showToolsPanel: false,
|
||||
enalbeVoicePanelShow: false,
|
||||
showEmojiPanel: false,
|
||||
// 扩大编辑器相关
|
||||
showExpandEditor: false,
|
||||
expandInputText: '',
|
||||
inputLineCount: 0,
|
||||
emojiList: ['😀','😃','😄','😁','😆','😅','🤣','😂','🙂','🙃','😉','😊','😇','🥰','😍','🤩','😘','😗','😚','😋','😛','😜','🤪','😝','🤑','🤗','🤭','🤫','🤔','🤐','🤨','😐','😑','😶','😏','😒','🙄','😬','🤥','😌','😔','😪','🤤','😴','😷','🤒','🤕','🤢','🤮','🤧','🥵','🥶','🥴','😵','🤯','🤠','🥳','😎','🤓','🧐','😕','😟','🙁','😮','😯','😲','😳','🥺','😦','😧','😨','😰','😥','😢','😭','😱','😖','😣','😞','😓','😩','😫','🥱','😤','😡','😠','🤬','😈','👿','💀','💩','👻','👽','🤖','🎃','😺','😸','😹','😻','😼','😽','🙀','😿','😾','👋','🤚','🖐','✋','🖖','👌','🤏','✌','🤞','🤟','🤘','🤙','👈','👉','👆','🖕','👇','☝','👍','👎','✊','👊','🤛','🤜','👏','🙌','👐','🤲','🤝','🙏','✍','💅','🤳','💪','💗','💓','💕','💖','💝','💞','💘','💌','💟','💛','💙','💜','🖤','💔','💢','💣','💥','💫','💦','💨','👁','👀','👅','👄','👂','👃','👶','👦','👧','👨','👩','👴','👵','👱','👲','👳','👴','👵','👶','👼','👸','🎅','🤶','🦸','🦹','🧙','🧚','🧛','🧜','🧝','🧞','🧟','🦄','🐶','🐱','🐭','🐹','🐰','🦊','🐻','🐼','🐨','🐯','🦁','🐮','🐷','🐸','🐵','🙈','🙉','🙊','🐒','🐔','🐧','🐦','🐤','🐣','🐥','🦆','🦅','🦉','🦇','🐺','🐗','🐴','🦄','🐝','🐛','🦋','🐌','🐞','🐜','🦟','🦗','🕷','🦂','🐢','🐍','🦎','🦖','🦕','🐙','🦑','🦐','🦞','🦀','🐡','🐠','🐟','🐬','🐳','🐋','🦈','🐊','🐅','🐆','🦓','🦍','🦧','🐘','🦛','🦏','🐪','🐫','🦒','🦘','🐃','🐂','🐄','🐎','🐖','🐏','🐑','🐐','🐓','🦃','🦚','🦜','🦢','🦩','🕊','🐕','🐩','🐈','🐓','🐇','🐁','🐀','🐿','🦔','🐾','🐉','🐲'],
|
||||
streamingMessage: null,
|
||||
streamInterval: null,
|
||||
streamContent: '',
|
||||
@@ -461,6 +526,11 @@ export default {
|
||||
return {
|
||||
bottom: this.keyboardHeight > 0 ? this.keyboardHeight + 'px' : '0px'
|
||||
};
|
||||
},
|
||||
canSendMessage() {
|
||||
const hasContent = this.inputText && this.inputText.trim() !== ''
|
||||
const hasEmoji = this.containsEmoji(this.inputText)
|
||||
return hasContent || hasEmoji
|
||||
}
|
||||
},
|
||||
onShow() {
|
||||
@@ -812,13 +882,17 @@ async loadChatHistoryIfExist() {
|
||||
|
||||
// 发送消息
|
||||
async sendMessage() {
|
||||
if (!this.inputText.trim()) return
|
||||
// 确保有内容或表情
|
||||
const hasContent = this.inputText && this.inputText.trim() !== ''
|
||||
const hasEmoji = this.containsEmoji(this.inputText)
|
||||
|
||||
if (!hasContent && !hasEmoji) return
|
||||
|
||||
const userMessage = {
|
||||
id: ++this.messageId,
|
||||
role: 'user',
|
||||
type: 'text',
|
||||
content: this.inputText.trim(),
|
||||
content: this.inputText,
|
||||
timestamp: Date.now()
|
||||
}
|
||||
this.shouldScrollToBottom = true
|
||||
@@ -846,10 +920,11 @@ async loadChatHistoryIfExist() {
|
||||
}
|
||||
|
||||
// 使用AI服务获取回复
|
||||
const enhancedMessage = this.enhanceEmojiMessage(userMessage.content)
|
||||
if (this.enableStreaming) {
|
||||
await this.sendStreamMessage(userMessage.content)
|
||||
await this.sendStreamMessage(enhancedMessage)
|
||||
} else {
|
||||
await this.sendNormalMessage(userMessage.content)
|
||||
await this.sendNormalMessage(enhancedMessage)
|
||||
}
|
||||
|
||||
} catch (error) {
|
||||
@@ -1071,11 +1146,8 @@ async loadChatHistoryIfExist() {
|
||||
|
||||
// 格式化时间
|
||||
formatTime(timestamp) {
|
||||
console.log('【调试】formatTime 接收到的时间戳:', timestamp, typeof timestamp);
|
||||
|
||||
// 如果没有时间戳,就不显示时间
|
||||
if (!timestamp) {
|
||||
console.warn('【调试】没有时间戳');
|
||||
return '';
|
||||
}
|
||||
|
||||
@@ -1108,21 +1180,15 @@ async loadChatHistoryIfExist() {
|
||||
date = new Date(timeValue);
|
||||
}
|
||||
|
||||
console.log('【调试】最终 Date 对象:', date);
|
||||
console.log('【调试】本地时间:', date.toLocaleString());
|
||||
console.log('【调试】小时:', date.getHours());
|
||||
console.log('【调试】分钟:', date.getMinutes());
|
||||
|
||||
// 如果时间无效,就不显示时间
|
||||
if (isNaN(date.getTime())) {
|
||||
console.warn('【调试】时间无效:', timestamp);
|
||||
return '';
|
||||
}
|
||||
|
||||
const hours = date.getHours().toString().padStart(2, '0');
|
||||
const minutes = date.getMinutes().toString().padStart(2, '0');
|
||||
const result = hours + ':' + minutes;
|
||||
console.log('【调试】最终显示时间:', result);
|
||||
return result;
|
||||
},
|
||||
|
||||
@@ -1251,6 +1317,22 @@ async loadChatHistoryIfExist() {
|
||||
this.showToolsPanel = false
|
||||
},
|
||||
|
||||
// 切换Emoji面板
|
||||
toggleEmojiPanel() {
|
||||
this.showEmojiPanel = !this.showEmojiPanel
|
||||
},
|
||||
|
||||
// 隐藏Emoji面板
|
||||
hideEmojiPanel() {
|
||||
this.showEmojiPanel = false
|
||||
},
|
||||
|
||||
// 插入Emoji
|
||||
insertEmoji(emoji) {
|
||||
this.inputText += emoji
|
||||
this.hideEmojiPanel()
|
||||
},
|
||||
|
||||
// 显示语音面板
|
||||
showVoicePanel() {
|
||||
this.enalbeVoicePanelShow = true
|
||||
@@ -1519,6 +1601,37 @@ async loadChatHistoryIfExist() {
|
||||
this.$emit('input-change', e.detail.value)
|
||||
},
|
||||
|
||||
// 输入框行数变化事件
|
||||
onLineChange(e) {
|
||||
this.inputLineCount = e.detail.lineCount || 0
|
||||
},
|
||||
|
||||
// 打开扩大编辑器
|
||||
openExpandEditor() {
|
||||
this.expandInputText = this.inputText
|
||||
this.showExpandEditor = true
|
||||
this.hideEmojiPanel()
|
||||
this.hideToolsPanel()
|
||||
},
|
||||
|
||||
// 关闭扩大编辑器
|
||||
closeExpandEditor() {
|
||||
this.showExpandEditor = false
|
||||
this.expandInputText = ''
|
||||
},
|
||||
|
||||
// 从扩大编辑器发送消息
|
||||
async sendFromExpandEditor() {
|
||||
if (!this.expandInputText.trim()) {
|
||||
return
|
||||
}
|
||||
|
||||
this.inputText = this.expandInputText
|
||||
this.closeExpandEditor()
|
||||
|
||||
await this.sendMessage()
|
||||
},
|
||||
|
||||
// 处理头像加载失败
|
||||
handleAvatarError() {
|
||||
this.avatarError = true
|
||||
@@ -1641,6 +1754,193 @@ async loadChatHistoryIfExist() {
|
||||
this.historyOffset = 0
|
||||
// 触发清空事件
|
||||
this.$emit('messages-cleared')
|
||||
},
|
||||
|
||||
// 检测字符串中是否包含表情
|
||||
containsEmoji(str) {
|
||||
const emojiReg = /[\u{1f300}-\u{1f9ff}\u{1f1e0}-\u{1f1ff}\u{2600}-\u{26ff}\u{2700}-\u{27bf}\u{1f900}-\u{1f9ff}\u{1f600}-\u{1f64f}\u{1f680}-\u{1f6ff}\u{200d}\u{2640}-\u{2642}\u{2300}-\u{23ff}\u{2b50}-\u{2bff}]/gu
|
||||
return emojiReg.test(str)
|
||||
},
|
||||
|
||||
// 根据表情生成适当的提示文本,帮助 AI 更好地理解
|
||||
enhanceEmojiMessage(content) {
|
||||
// 常见表情的含义映射
|
||||
const emojiResponses = {
|
||||
'😀': '[开心]',
|
||||
'😂': '[大笑]',
|
||||
'😊': '[微笑]',
|
||||
'❤️': '[爱心]',
|
||||
'👍': '[点赞]',
|
||||
'😭': '[哭泣]',
|
||||
'🙏': '[感谢/拜托]',
|
||||
'😍': '[喜欢]',
|
||||
'🎉': '[庆祝]',
|
||||
'🤔': '[思考]',
|
||||
'😅': '[尴尬]',
|
||||
'😁': '[开心]',
|
||||
'🥰': '[喜爱]',
|
||||
'😘': '[飞吻]',
|
||||
'😏': '[坏笑]',
|
||||
'🥳': '[庆祝]',
|
||||
'😔': '[难过]',
|
||||
'😢': '[哭泣]',
|
||||
'😤': '[生气]',
|
||||
'😴': '[困]',
|
||||
'🤗': '[拥抱]',
|
||||
'🙂': '[微笑]',
|
||||
'😃': '[开心]',
|
||||
'😄': '[大笑]',
|
||||
'😆': '[开心]',
|
||||
'😇': '[天使]',
|
||||
'🤩': '[惊喜]',
|
||||
'😋': '[好吃]',
|
||||
'😛': '[调皮]',
|
||||
'😜': '[调皮]',
|
||||
'🤪': '[搞怪]',
|
||||
'😝': '[开心]',
|
||||
'🤑': '[发财]',
|
||||
'🤭': '[害羞]',
|
||||
'🤫': '[嘘]',
|
||||
'🤐': '[闭嘴]',
|
||||
'🤨': '[疑惑]',
|
||||
'😐': '[无语]',
|
||||
'😑': '[无语]',
|
||||
'😶': '[沉默]',
|
||||
'😒': '[不屑]',
|
||||
'🙄': '[白眼]',
|
||||
'😬': '[尴尬]',
|
||||
'🤥': '[说谎]',
|
||||
'😌': '[安心]',
|
||||
'😪': '[困]',
|
||||
'🤤': '[流口水]',
|
||||
'😷': '[生病]',
|
||||
'🤒': '[发烧]',
|
||||
'🤕': '[受伤]',
|
||||
'🤢': '[恶心]',
|
||||
'🤮': '[呕吐]',
|
||||
'🤧': '[感冒]',
|
||||
'🥵': '[热]',
|
||||
'🥶': '[冷]',
|
||||
'🥴': '[头晕]',
|
||||
'😵': '[晕]',
|
||||
'🤯': '[爆炸]',
|
||||
'🤠': '[酷]',
|
||||
'😎': '[酷]',
|
||||
'🤓': '[书呆子]',
|
||||
'🧐': '[疑惑]',
|
||||
'😕': '[困惑]',
|
||||
'😟': '[担心]',
|
||||
'🙁': '[难过]',
|
||||
'😮': '[惊讶]',
|
||||
'😯': '[惊讶]',
|
||||
'😲': '[震惊]',
|
||||
'😳': '[脸红]',
|
||||
'🥺': '[恳求]',
|
||||
'😦': '[惊讶]',
|
||||
'😧': '[惊讶]',
|
||||
'😨': '[害怕]',
|
||||
'😰': '[紧张]',
|
||||
'😥': '[失望]',
|
||||
'😱': '[恐惧]',
|
||||
'😖': '[困扰]',
|
||||
'😣': '[痛苦]',
|
||||
'😞': '[难过]',
|
||||
'😓': '[汗]',
|
||||
'😩': '[累]',
|
||||
'😫': '[累]',
|
||||
'🥱': '[困]',
|
||||
'😡': '[愤怒]',
|
||||
'😠': '[生气]',
|
||||
'🤬': '[咒骂]',
|
||||
'😈': '[恶魔]',
|
||||
'👿': '[生气]',
|
||||
'💀': '[骷髅]',
|
||||
'💩': '[便便]',
|
||||
'👻': '[鬼]',
|
||||
'👽': '[外星人]',
|
||||
'🤖': '[机器人]',
|
||||
'🎃': '[万圣节]',
|
||||
'😺': '[开心猫]',
|
||||
'😸': '[微笑猫]',
|
||||
'😹': '[大笑猫]',
|
||||
'😻': '[花痴猫]',
|
||||
'😼': '[得意猫]',
|
||||
'😽': '[亲亲猫]',
|
||||
'🙀': '[惊讶猫]',
|
||||
'😿': '[哭泣猫]',
|
||||
'😾': '[生气猫]',
|
||||
'👋': '[挥手]',
|
||||
'🤚': '[举手]',
|
||||
'🖐': '[手掌]',
|
||||
'✋': '[手掌]',
|
||||
'🖖': '[V]',
|
||||
'👌': '[OK]',
|
||||
'🤏': '[捏]',
|
||||
'✌️': '[耶]',
|
||||
'🤞': '[好运]',
|
||||
'🤟': '[爱你]',
|
||||
'🤘': '[摇滚]',
|
||||
'🤙': '[打电话]',
|
||||
'👈': '[左边]',
|
||||
'👉': '[右边]',
|
||||
'👆': '[上边]',
|
||||
'🖕': '[竖中指]',
|
||||
'👇': '[下边]',
|
||||
'☝': '[向上]',
|
||||
'👎': '[鄙视]',
|
||||
'✊': '[拳头]',
|
||||
'👊': '[拳头]',
|
||||
'🤛': '[左拳]',
|
||||
'🤜': '[右拳]',
|
||||
'👏': '[鼓掌]',
|
||||
'🙌': '[举手庆祝]',
|
||||
'👐': '[张开手]',
|
||||
'🤲': '[摊手]',
|
||||
'🤝': '[握手]',
|
||||
'✍️': '[写字]',
|
||||
'💅': '[美甲]',
|
||||
'🤳': '[自拍]',
|
||||
'💪': '[肌肉]',
|
||||
'💗': '[爱心]',
|
||||
'💓': '[心跳]',
|
||||
'💕': '[两颗心]',
|
||||
'💖': '[闪亮心]',
|
||||
'💝': '[礼物心]',
|
||||
'💞': '[旋转心]',
|
||||
'💘': '[丘比特]',
|
||||
'💌': '[情书]',
|
||||
'💟': '[心形]',
|
||||
'💛': '[黄心]',
|
||||
'💙': '[蓝心]',
|
||||
'💜': '[紫心]',
|
||||
'🖤': '[黑心]',
|
||||
'💔': '[心碎]',
|
||||
'💢': '[愤怒]',
|
||||
'💣': '[炸弹]',
|
||||
'💥': '[爆炸]',
|
||||
'💫': '[头晕]',
|
||||
'💦': '[汗]',
|
||||
'💨': '[风]',
|
||||
'👁️': '[眼睛]',
|
||||
'👀': '[看]',
|
||||
'👅': '[舌头]',
|
||||
'👄': '[嘴巴]',
|
||||
'👂': '[耳朵]',
|
||||
'👃': '[鼻子]'
|
||||
}
|
||||
|
||||
// 如果是纯表情消息,添加一些提示
|
||||
if (this.containsEmoji(content) && !content.match(/[\u4e00-\u9fa5a-zA-Z]/)) {
|
||||
let enhancedMessage = content
|
||||
// 为表情添加描述
|
||||
for (let emoji in emojiResponses) {
|
||||
if (content.includes(emoji)) {
|
||||
enhancedMessage += ` (${emojiResponses[emoji]})`
|
||||
}
|
||||
}
|
||||
return enhancedMessage
|
||||
}
|
||||
return content
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2375,13 +2675,33 @@ $radius-lg: 36rpx;
|
||||
line-height: 1.5;
|
||||
border: 1rpx solid #e5e5e5;
|
||||
color: #333;
|
||||
|
||||
margin-right: -50rpx;
|
||||
&::placeholder {
|
||||
color: #999;
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
|
||||
/* Emoji按钮 */
|
||||
.emoji-btn {
|
||||
width: 89rpx;
|
||||
height: 89rpx;
|
||||
border-radius: 12rpx;
|
||||
|
||||
margin-left: 2rpx;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
border: none;
|
||||
padding: 0;
|
||||
left:43rpx;
|
||||
|
||||
.iconfont {
|
||||
font-size: 36rpx;
|
||||
line-height: 1;
|
||||
}
|
||||
}
|
||||
|
||||
/* 发送按钮 - 微信聊天样式 */
|
||||
.send-btn {
|
||||
width: 120rpx;
|
||||
@@ -2419,7 +2739,7 @@ $radius-lg: 36rpx;
|
||||
width: 120rpx;
|
||||
height: 72rpx;
|
||||
border-radius: 12rpx;
|
||||
font-size: 28rpx;
|
||||
font-size: 33rpx;
|
||||
margin-top: 0rpx;
|
||||
margin-bottom: 0rpx;
|
||||
}
|
||||
@@ -3226,7 +3546,246 @@ $radius-lg: 36rpx;
|
||||
width: 120rpx;
|
||||
height: 72rpx;
|
||||
border-radius: 12rpx;
|
||||
font-size: 28rpx;
|
||||
font-size: 33rpx;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Emoji面板 */
|
||||
.emoji-popup {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
z-index: 999;
|
||||
|
||||
.emoji-mask {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
background-color: rgba(0, 0, 0, 0.4);
|
||||
backdrop-filter: blur(6rpx);
|
||||
}
|
||||
|
||||
.emoji-panel {
|
||||
position: absolute;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
background-color: #fff;
|
||||
border-radius: 24rpx 24rpx 0 0;
|
||||
padding: 0;
|
||||
box-shadow: 0 -2rpx 10rpx rgba(0, 0, 0, 0.05);
|
||||
max-height: 55vh;
|
||||
|
||||
.emoji-header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
padding: 16rpx 20rpx;
|
||||
border-bottom: 1rpx solid #e5e5e5;
|
||||
background-color: #f7f7f7;
|
||||
|
||||
text {
|
||||
font-size: 30rpx;
|
||||
font-weight: 500;
|
||||
color: #333;
|
||||
}
|
||||
|
||||
.close-btn {
|
||||
width: 48rpx;
|
||||
height: 48rpx;
|
||||
border-radius: 50%;
|
||||
background-color: transparent;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
border: none;
|
||||
|
||||
&:hover {
|
||||
background-color: #e5e5e5;
|
||||
}
|
||||
|
||||
text {
|
||||
font-size: 36rpx;
|
||||
color: #999;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.emoji-grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(8, 1fr);
|
||||
gap: 8rpx;
|
||||
padding: 20rpx 16rpx;
|
||||
overflow-y: auto;
|
||||
max-height: 45vh;
|
||||
|
||||
.emoji-item {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
width: 100%;
|
||||
height: 80rpx;
|
||||
border-radius: 8rpx;
|
||||
background-color: transparent;
|
||||
transition: all 0.15s ease;
|
||||
|
||||
&:hover {
|
||||
background-color: #f5f5f5;
|
||||
}
|
||||
|
||||
&:active {
|
||||
background-color: #e5e5e5;
|
||||
}
|
||||
|
||||
.emoji-text {
|
||||
font-size: 48rpx;
|
||||
line-height: 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* 扩大按钮 */
|
||||
.expand-btn {
|
||||
width: 72rpx;
|
||||
height: 72rpx;
|
||||
border-radius: 12rpx;
|
||||
margin-left: 12rpx;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
border: none;
|
||||
background-color: #f2f2f2;
|
||||
padding: 0;
|
||||
left:60rpx;
|
||||
|
||||
.iconfont {
|
||||
font-size: 36rpx;
|
||||
line-height: 1;
|
||||
}
|
||||
}
|
||||
|
||||
/* 扩大编辑器弹窗 */
|
||||
.expand-editor-popup {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
z-index: 1000;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
|
||||
.expand-editor-mask {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
background-color: rgba(0, 0, 0, 0.4);
|
||||
backdrop-filter: blur(6rpx);
|
||||
}
|
||||
|
||||
.expand-editor-panel {
|
||||
position: relative;
|
||||
flex: 1;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
background-color: #fff;
|
||||
border-radius: 0;
|
||||
margin-top: 100rpx;
|
||||
|
||||
.expand-editor-header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
padding: 24rpx 32rpx;
|
||||
border-bottom: 1rpx solid #e5e5e5;
|
||||
background-color: #f9f9f9;
|
||||
|
||||
text {
|
||||
font-size: 32rpx;
|
||||
font-weight: 500;
|
||||
color: #333;
|
||||
}
|
||||
|
||||
.close-btn {
|
||||
width: 64rpx;
|
||||
height: 64rpx;
|
||||
border-radius: 50%;
|
||||
background-color: transparent;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
border: none;
|
||||
padding: 0;
|
||||
|
||||
text {
|
||||
font-size: 48rpx;
|
||||
color: #999;
|
||||
line-height: 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.expand-editor-input {
|
||||
flex: 1;
|
||||
min-height: 300rpx;
|
||||
max-height: none;
|
||||
padding: 32rpx;
|
||||
font-size: 30rpx;
|
||||
line-height: 1.6;
|
||||
background-color: #fff;
|
||||
border: none;
|
||||
color: #333;
|
||||
}
|
||||
|
||||
.expand-editor-footer {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
padding: 24rpx 32rpx;
|
||||
border-top: 1rpx solid #e5e5e5;
|
||||
background-color: #f9f9f9;
|
||||
padding-bottom: calc(24rpx + env(safe-area-inset-bottom));
|
||||
|
||||
.expand-cancel-btn {
|
||||
width: 160rpx;
|
||||
height: 80rpx;
|
||||
border-radius: 40rpx;
|
||||
background-color: #f2f2f2;
|
||||
color: #666;
|
||||
font-size: 28rpx;
|
||||
border: none;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.expand-send-btn {
|
||||
width: 160rpx;
|
||||
height: 80rpx;
|
||||
border-radius: 40rpx;
|
||||
background-color: #07c160;
|
||||
color: #fff;
|
||||
font-size: 28rpx;
|
||||
font-weight: 500;
|
||||
border: none;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
|
||||
&[disabled] {
|
||||
background-color: #ccc;
|
||||
opacity: 0.7;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -248,7 +248,8 @@ export default {
|
||||
latitude: 0,
|
||||
longitude: 0,
|
||||
},
|
||||
personnel_bg: ''
|
||||
personnel_bg: '',
|
||||
mpShareData: null //小程序分享数据
|
||||
};
|
||||
},
|
||||
onLoad(option) {
|
||||
@@ -303,6 +304,24 @@ export default {
|
||||
});
|
||||
},
|
||||
onShow() {
|
||||
// #ifdef MP-WEIXIN
|
||||
this.$util.getMpShare('/pages_tool/contact/contact').then(res => {
|
||||
this.mpShareData = res;
|
||||
}).catch(err => {
|
||||
// 如果后台没配置,用默认值
|
||||
this.mpShareData = {
|
||||
appMessage: {
|
||||
title: '联系我们',
|
||||
path: '/pages_tool/contact/contact'
|
||||
},
|
||||
timeLine: {
|
||||
title: '联系我们',
|
||||
query: ''
|
||||
}
|
||||
};
|
||||
});
|
||||
// #endif
|
||||
|
||||
this.$util.hideHomeButton();
|
||||
},
|
||||
methods: {
|
||||
@@ -449,9 +468,28 @@ export default {
|
||||
longitude: parseFloat(this.shop.longitude),
|
||||
name: this.$lang('oneClickNavigation'),
|
||||
});
|
||||
}
|
||||
}
|
||||
},
|
||||
onShareAppMessage() {
|
||||
return this.mpShareData?.appMessage || {
|
||||
title: '联系我们',
|
||||
path: '/pages_tool/contact/contact'
|
||||
};
|
||||
},
|
||||
onShareTimeline() {
|
||||
return this.mpShareData?.timeLine || {
|
||||
title: '联系我们',
|
||||
query: ''
|
||||
};
|
||||
},
|
||||
onAddToFavorites() {
|
||||
return {
|
||||
title: '联系我们',
|
||||
path: '/pages_tool/contact/contact'
|
||||
};
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
|
||||
@@ -134,7 +134,8 @@ export default {
|
||||
levelId: 0,
|
||||
levelInfo: {
|
||||
bg_color: '#333'
|
||||
}
|
||||
},
|
||||
mpShareData: null //小程序分享数据
|
||||
};
|
||||
},
|
||||
onLoad() {
|
||||
@@ -161,7 +162,26 @@ export default {
|
||||
});
|
||||
this.levelInfo = levelInfo;
|
||||
},
|
||||
onShow() { },
|
||||
onShow() {
|
||||
//小程序分享
|
||||
// #ifdef MP-WEIXIN
|
||||
this.$util.getMpShare('/pages_tool/member/card').then(res => {
|
||||
this.mpShareData = res;
|
||||
}).catch(err => {
|
||||
// 如果后台没配置,用默认值
|
||||
this.mpShareData = {
|
||||
appMessage: {
|
||||
title: '专属会员权益,快来体验',
|
||||
path: '/pages_tool/member/card'
|
||||
},
|
||||
timeLine: {
|
||||
title: '专属会员权益,快来体验',
|
||||
query: '/pages_tool/member/card'
|
||||
}
|
||||
};
|
||||
});
|
||||
// #endif
|
||||
},
|
||||
methods: {
|
||||
headimgError() {
|
||||
this.memberInfo.headimg = this.$util.getDefaultImage().head;
|
||||
@@ -185,6 +205,24 @@ export default {
|
||||
}
|
||||
this.$util.redirectTo(this.$util.MEMBER_PAGE_URL);
|
||||
return true;
|
||||
},
|
||||
onShareAppMessage() {
|
||||
return this.mpShareData?.appMessage || {
|
||||
title: '专属会员权益,快来体验',
|
||||
path: '/pages_tool/member/card'
|
||||
};
|
||||
},
|
||||
onShareTimeline() {
|
||||
return this.mpShareData?.timeLine || {
|
||||
title: '专属会员权益,快来体验',
|
||||
query: '/pages_tool/member/card'
|
||||
};
|
||||
},
|
||||
onAddToFavorites() {
|
||||
return {
|
||||
title: '专属会员权益,快来体验',
|
||||
path: '/pages_tool/member/card'
|
||||
};
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
Reference in New Issue
Block a user