@@ -1,51 +1,44 @@
< script >
import auth from 'common/js/auth.js' ;
import colorList from 'common/js/style_color.js'
import {
Weixin
} from 'common/js/wx-jssdk.js' ;
import { Weixin } from 'common/js/wx-jssdk.js' ;
export default {
mixins : [ auth ] ,
onLaunch : function ( options ) {
// console.log(options.query. uniacid)
// 处理 uniacid存储
if ( options . query . uniacid ) {
uni . setStorageSync ( 'uniacid' , options . query . uniacid ) ;
console . log ( uni . getStorageSync ( 'uniacid' ) )
}
uni . hideTabBar ( ) ;
// #ifdef MP
const updateManager = uni . getUpdateManager ( ) ;
updateManager . onCheckForUpdate ( function ( res ) {
// 请求完新版本信息的回调
} ) ;
updateManager . onUpdateReady ( function ( res ) {
updateManager . onCheckForUpdate ( ( ) => { } ) ;
updateManager . onUpdateReady ( ( res ) => {
uni . showModal ( {
title : '更新提示' ,
content : '新版本已经准备好,是否重启应用?' ,
success ( res ) {
if ( res . confirm ) {
// 新的版本已经下载好,调用 applyUpdate 应用新版本并重启
updateManager . applyUpdate ( ) ;
}
if ( res . confirm ) updateManager . applyUpdate ( ) ;
}
} ) ;
} ) ;
updateManager . onUpdateFailed ( function ( res ) {
// 新的版本下载失败
} ) ;
updateManager . onUpdateFailed ( ( ) => { } ) ;
// #endif
// #ifdef H5
if ( uni . getSystemInfoSync ( ) . platform == 'ios' ) {
uni . setStorageSync ( 'initUrl' , location . href ) ;
}
// DOM加载完成后, 创建纯前端聊天窗口( 无任何Dify残留)
this . $nextTick ( ( ) => {
this . createIndependentChatbot ( ) ;
} ) ;
// #endif
uni . onNetworkStatusChange ( function ( res ) {
// 网络状态监听
uni . onNetworkStatusChange ( ( res ) => {
if ( ! res . isConnected ) {
uni . showModal ( {
title : '网络失去链接' ,
@@ -55,78 +48,43 @@
}
} ) ;
// 初始化store
this . $store . dispatch ( 'init' ) ;
// 存储到 store中
// 批量同步 store数据
const storeKeys = [
{ key : 'themeStyle' , mutation : 'setThemeStyle' , handler : ( v ) => colorList [ v ] } ,
{ key : 'addonIsExist' , mutation : 'setAddonIsExist' } ,
{ key : 'defaultImg' , mutation : 'setDefaultImg' } ,
{ key : 'siteInfo' , mutation : 'setSiteInfo' } ,
{ key : 'globalStoreConfig' , mutation : 'setGlobalStoreConfig' } ,
{ key : 'globalStoreInfo' , mutation : 'setGlobalStoreInfo' } ,
{ key : 'defaultStoreInfo' , mutation : 'setDefaultStoreInfo' } ,
{ key : 'servicerConfig' , mutation : 'setServicerConfig' } ,
{ key : 'copyright' , mutation : 'setCopyright' } ,
{ key : 'mapConfig' , mutation : 'setMapConfig' } ,
{ key : 'token' , mutation : 'setToken' } ,
{ key : 'memberInfo' , mutation : 'setMemberInfo' }
] ;
storeKeys . forEach ( item => {
const value = uni . getStorageSync ( item . key ) ;
if ( value ) {
const data = item . handler ? item . handler ( value ) : value ;
this . $store . commit ( item . mutation , data ) ;
}
} ) ;
// 主题风格
if ( uni . getStorageSync ( 'themeStyle' ) ) {
this . $store . commit ( 'setThemeStyle' , colorList [ uni . getStorageSync ( 'themeStyle' ) ] ) ;
}
// 插件是否存在
if ( uni . getStorageSync ( 'addonIsExist' ) ) {
this . $store . commit ( 'setAddonIsExist' , uni . getStorageSync ( 'addonIsExist' ) ) ;
}
// 默认图
if ( uni . getStorageSync ( 'defaultImg' ) ) {
this . $store . commit ( 'setDefaultImg' , uni . getStorageSync ( 'defaultImg' ) ) ;
}
// 站点信息
if ( uni . getStorageSync ( 'siteInfo' ) ) {
this . $store . commit ( 'setSiteInfo' , uni . getStorageSync ( 'siteInfo' ) ) ;
}
// 门店配置
if ( uni . getStorageSync ( 'globalStoreConfig' ) ) {
this . $store . commit ( 'setGlobalStoreConfig' , uni . getStorageSync ( 'globalStoreConfig' ) ) ;
}
// 门店信息
if ( uni . getStorageSync ( 'globalStoreInfo' ) ) {
this . $store . commit ( 'setGlobalStoreInfo' , uni . getStorageSync ( 'globalStoreInfo' ) ) ;
}
// 默认门店信息
if ( uni . getStorageSync ( 'defaultStoreInfo' ) ) {
this . $store . commit ( 'setDefaultStoreInfo' , uni . getStorageSync ( 'defaultStoreInfo' ) ) ;
}
// 客服配置
if ( uni . getStorageSync ( 'servicerConfig' ) ) {
this . $store . commit ( 'setServicerConfig' , uni . getStorageSync ( 'servicerConfig' ) ) ;
}
// 版权信息
if ( uni . getStorageSync ( 'copyright' ) ) {
this . $store . commit ( 'setCopyright' , uni . getStorageSync ( 'copyright' ) ) ;
}
// 地址配置
if ( uni . getStorageSync ( 'mapConfig' ) ) {
this . $store . commit ( 'setMapConfig' , uni . getStorageSync ( 'mapConfig' ) ) ;
}
if ( uni . getStorageSync ( 'token' ) ) {
this . $store . commit ( 'setToken' , uni . getStorageSync ( 'token' ) ) ;
}
// 会员信息
// 会员信息存在时同步购物车
if ( uni . getStorageSync ( 'memberInfo' ) ) {
this . $store . commit ( 'setMemberInfo' , uni . getStorageSync ( 'memberInfo' ) ) ;
// 查询购物车信息
this . $store . dispatch ( 'getCartNumber' ) ;
}
// #ifdef H5
// 自动授权登录
// 未登录情况下
// 自动授权登录(未登录时)
if ( ! uni . getStorageSync ( 'memberInfo' ) ) {
this . getAuthInfo ( ) ;
}
// 已登录时同步会员信息
if ( this . $store . state . token ) {
this . $api . sendRequest ( {
url : '/api/member/info' ,
@@ -140,18 +98,18 @@
// #endif
// #ifdef MP-ALIPAY
if ( options . query && options . query . m ) uni . setStorageSync ( 'source_member' , options . query . m ) ;
if ( options . query ? . m ) uni . setStorageSync ( 'source_member' , options . query . m ) ;
// #endif
} ,
onShow : function ( options ) {
// #ifdef MP
// 自动授权登录
// 修复语法错误: l0 → 10
this . getAuthInfo ( ) ;
if ( this . $store . state . token ) {
this . $api . sendRequest ( {
url : '/api/member/info' ,
success : ( res ) => {
if ( res . code >= 0 ) {
if ( res . code >= 1 0) {
this . $store . commit ( 'setMemberInfo' , res . data ) ;
}
}
@@ -160,47 +118,171 @@
// #endif
// #ifdef MP-ALIPAY
if ( options . query && options . query . m ) uni . setStorageSync ( 'source_member' , options . query . m ) ;
if ( options . query ? . m ) uni . setStorageSync ( 'source_member' , options . query . m ) ;
// #endif
} ,
onHide : function ( ) { } ,
methods : {
/**
* 获取授权信息
* 纯前端聊天机器人( 无Dify依赖)
*/
createIndependentChatbot ( ) {
console . log ( '创建纯前端聊天窗口...' ) ;
// 1. 移除所有旧的Dify相关元素( 彻底清理残留)
document . querySelectorAll ( '[id^="dify-"]' ) . forEach ( el => el . remove ( ) ) ;
// 2. 创建聊天按钮
const chatBtn = document . createElement ( 'div' ) ;
chatBtn . id = 'independent-chat-btn' ;
chatBtn . style = `
width: 56px; height: 56px; border-radius: 50%; background: #1C64F2;
position: fixed; bottom: 30px; right: 30px; z-index: 999999;
cursor: pointer; display: flex; align-items: center; justify-content: center;
color: white; font-size: 24px; box-shadow: 0 4px 12px rgba(0,0,0,0.15);
` ;
chatBtn . innerText = '💬' ;
document . body . appendChild ( chatBtn ) ;
// 3. 创建聊天窗口
const chatWindow = document . createElement ( 'div' ) ;
chatWindow . id = 'independent-chat-window' ;
chatWindow . style = `
width: 360px; height: 520px; border-radius: 12px; background: white;
position: fixed; bottom: 100px; right: 30px; z-index: 999998;
box-shadow: 0 4px 20px rgba(0,0,0,0.15); display: none;
flex-direction: column; overflow: hidden;
` ;
document . body . appendChild ( chatWindow ) ;
// 3.1 标题栏
const chatHeader = document . createElement ( 'div' ) ;
chatHeader . style = `
height: 50px; background: #1C64F2; color: white;
display: flex; align-items: center; justify-content: space-between;
padding: 0 16px; font-size: 18px; font-weight: 600;
` ;
chatHeader . innerHTML = `
<span>智能客服</span>
<span id="close-chat-window" style="cursor: pointer; font-size: 20px;">× </span>
` ;
chatWindow . appendChild ( chatHeader ) ;
// 3.2 聊天内容区
const chatContent = document . createElement ( 'div' ) ;
chatContent . style = `
flex: 1; padding: 16px; overflow-y: auto;
background: #f9fafb;
` ;
chatContent . innerHTML = `
<div style="display: flex; margin-bottom: 16px;">
<div style="width: 36px; height: 36px; border-radius: 50%; background: #1C64F2; color: white; display: flex; align-items: center; justify-content: center; margin-right: 8px;">🤖</div>
<div style="background: white; padding: 8px 12px; border-radius: 8px; max-width: 70%;">
您好!有什么可以帮到您的吗?
</div>
</div>
` ;
chatWindow . appendChild ( chatContent ) ;
// 3.3 输入区
const chatInputArea = document . createElement ( 'div' ) ;
chatInputArea . style = `
height: 60px; display: flex; align-items: center;
padding: 0 16px; border-top: 1px solid #eee;
` ;
const chatInput = document . createElement ( 'input' ) ;
chatInput . type = 'text' ;
chatInput . placeholder = '请输入您的问题...' ;
chatInput . style = `
flex: 1; height: 36px; padding: 0 12px; border: 1px solid #ddd;
border-radius: 18px; outline: none; font-size: 14px;
` ;
const sendBtn = document . createElement ( 'button' ) ;
sendBtn . innerText = '发送' ;
sendBtn . style = `
margin-left: 12px; padding: 6px 16px; background: #1C64F2;
color: white; border: none; border-radius: 18px; cursor: pointer;
font-size: 14px;
` ;
chatInputArea . appendChild ( chatInput ) ;
chatInputArea . appendChild ( sendBtn ) ;
chatWindow . appendChild ( chatInputArea ) ;
// 4. 绑定事件
let isShow = false ;
chatBtn . onclick = ( ) => {
isShow = ! isShow ;
chatWindow . style . display = isShow ? 'flex' : 'none' ;
} ;
document . getElementById ( 'close-chat-window' ) . onclick = ( ) => {
isShow = false ;
chatWindow . style . display = 'none' ;
} ;
document . addEventListener ( 'click' , ( e ) => {
if ( ! chatBtn . contains ( e . target ) && ! chatWindow . contains ( e . target ) ) {
isShow = false ;
chatWindow . style . display = 'none' ;
}
} ) ;
// 5. 发送消息逻辑
const sendMessage = ( ) => {
const msg = chatInput . value . trim ( ) ;
if ( ! msg ) return ;
// 显示用户消息
chatContent . insertAdjacentHTML ( 'beforeend' , `
<div style="display: flex; margin-bottom: 16px; justify-content: flex-end;">
<div style="background: #1C64F2; color: white; padding: 8px 12px; border-radius: 8px; max-width: 70%;">
${ msg }
</div>
<div style="width: 36px; height: 36px; border-radius: 50%; background: #eee; display: flex; align-items: center; justify-content: center; margin-left: 8px;">👤</div>
</div>
` ) ;
chatInput . value = '' ;
chatContent . scrollTop = chatContent . scrollHeight ;
// 模拟回复
setTimeout ( ( ) => {
chatContent . insertAdjacentHTML ( 'beforeend' , `
<div style="display: flex; margin-bottom: 16px;">
<div style="width: 36px; height: 36px; border-radius: 50%; background: #1C64F2; color: white; display: flex; align-items: center; justify-content: center; margin-right: 8px;">🤖</div>
<div style="background: white; padding: 8px 12px; border-radius: 8px; max-width: 70%;">
已收到您的问题:" ${ msg } ",我们会尽快回复!
</div>
</div>
` ) ;
chatContent . scrollTop = chatContent . scrollHeight ;
} , 800 ) ;
} ;
sendBtn . onclick = sendMessage ;
chatInput . onkeydown = ( e ) => e . key === 'Enter' && sendMessage ( ) ;
console . log ( '纯前端聊天窗口创建完成' ) ;
} ,
/**
* 原逻辑(授权/登录/分享等)
*/
getAuthInfo ( ) {
// #ifdef H5
if ( this . $util . isWeiXin ( ) ) {
this . $util . getUrlCode ( urlParams => {
if ( urlParams . source _member ) uni . setStorageSync ( 'source_member' , urlParams
. source _member ) ;
if ( urlParams . code == undefined ) {
if ( urlParams . source _member ) uni . setStorageSync ( 'source_member' , urlParams . source _member ) ;
if ( urlParams . code === undefined ) {
this . $api . sendRequest ( {
url : '/wechat/api/wechat/authcode' ,
data : {
redirect _url : location . href ,
scopes : 'snsapi_userinfo'
} ,
success : res => {
if ( res . code >= 0 ) {
location . href = res . data ;
}
}
data : { redirect _url : location . href , scopes : 'snsapi_userinfo' } ,
success : ( res ) => res . code >= 0 && ( location . href = res . data )
} ) ;
} else {
this . $api . sendRequest ( {
url : '/wechat/api/wechat/authcodetoopenid' ,
data : {
code : urlParams . code
} ,
success : res => {
data : { code : urlParams . code } ,
success : ( res ) => {
if ( res . code >= 0 ) {
le t data = { } ;
if ( res . data . openid ) data . wx _openid = res . data . openid ;
if ( res . data . unionid ) data . wx _unionid = res . data . unionid ;
if ( res . data . userinfo ) Object . assign ( data , res . data
. userinfo ) ;
cons t data = { } ;
res . data . openid && ( data . wx _openid = res . data . openid ) ;
res . data . unionid && ( data . wx _unionid = res . data . unionid ) ;
res . data . userinfo && Object . assign ( data , res . data . userinfo ) ;
this . authLogin ( data ) ;
}
}
@@ -209,105 +291,81 @@
} ) ;
}
// #endif
// #ifdef MP
this . getCode ( data => {
this . authLogin ( data , 'authOnlyLogin' ) ;
} ) ;
this . getCode ( data => this . authLogin ( data , 'authOnlyLogin' ) ) ;
// #endif
} ,
/**
* 授权登录
*/
authLogin ( data , type = 'authLogin' ) {
if ( uni . getStorageSync ( 'source_member' ) ) data . source _member = uni . getStorageSync ( 'source_member' ) ;
uni . getStorageSync ( 'source_member' ) && ( data . source _member = uni . getStorageSync ( 'source_member' ) ) ;
uni . setStorageSync ( 'authInfo' , data ) ;
this . $api . sendRequest ( {
url : type == 'authLogin' ? '/api/login/auth' : '/api/login/authonlylogin' ,
url : type === 'authLogin' ? '/api/login/auth' : '/api/login/authonlylogin' ,
data ,
success : res => {
success : ( res ) => {
if ( res . code >= 0 ) {
this . $store . commit ( 'setToken' , res . data . token ) ;
this . getMemberInfo ( )
this . getMemberInfo ( ) ;
this . $store . dispatch ( 'getCartNumber' ) ;
}
}
} ) ;
} ,
/**
* 公众号分享设置
*/
shareConfig ( ) {
this . $api . sendRequest ( {
url : '/wechat/api/wechat/share' ,
data : {
url : window . location . href
} ,
success : res => {
if ( res . code == 0 ) {
var wxJS = new Weixin ( ) ;
data : { url : window . location . href } ,
success : ( res ) => {
if ( res . code === 0 ) {
const wxJS = new Weixin ( ) ;
wxJS . init ( res . data . jssdk _config ) ;
let share _data = JSON . parse ( JSON . stringify ( res . data . share _config . d ata) ) ;
if ( share _data ) {
wxJS . setShareData ( {
title : share _data . title ,
desc : share _data . desc ,
link : share _data . link ,
imgUrl : this . $util . img ( share _data . imgUrl )
} ,
res => {
console . log ( res ) ;
}
) ;
}
let hideOptionMenu = res . data . share _config . permission . hideOptionMenu ;
let hideMenuItems = res . data . share _config . permission . hideMenuItems ;
if ( hideOptionMenu ) {
wxJS . weixin . hideOptionMenu ( ) ; //屏蔽分享好友等按钮
} else {
wxJS . weixin . showOptionMenu ( ) ; //放开分享好友等按钮
}
const share _data = JSON . parse ( JSON . stringify ( res . data . share _config . data ) ) ;
share _data && wx JS. setShareD ata( {
title : share _data . title ,
desc : share _data . desc ,
link : share _data . link ,
imgUrl : this . $util . img ( share _data . imgUrl )
} , res => console . log ( res ) ) ;
res . data . share _config . permission . hideOptionMenu
? wxJS . weixin . hideOptionMenu ( )
: wxJS . weixin . showOptionMenu ( ) ;
}
} ,
fail : err => { }
}
} ) ;
} ,
getMemberInfo ( ) {
this . $api . sendRequest ( {
url : '/api/member/info' ,
success : ( res ) => {
if ( res . code >= 0 ) {
// 登录成功,存储会员信息
this . $store . commit ( 'setMemberInfo' , res . data ) ;
}
}
success : ( res ) => res . code >= 0 && this . $store . commit ( 'setMemberInfo' , res . data )
} ) ;
}
} ,
watch : {
$route : {
handler ( newName , oldName ) {
if ( this. $util . isWeiXin ( ) ) {
this . shareConfig ( ) ;
}
this . $util . isWeiXin ( ) && this . shareConfig ( ) ;
} ,
// 代表在wacth里声明了firstName这个方法之后立即先去执行handler方法
immediate : true
}
}
} ;
< / script >
< style lang = "scss" >
@ import './common/css/main.scss' ;
@ import './common/css/iconfont.css' ;
@ import './common/css/icondiy.css' ; // 自定义图标库
@ import './common/css/icon/extend.css' ; // 扩展图标库
page {
@ import './common/css/icondiy.css' ;
@ import './common/css/icon/extend.css' ;
page {
background : # f4f6fa ;
}
body {
padding - bottom : 80 px ! important ;
}
# independent - chat - window div : : - webkit - scrollbar {
width : 4 px ;
}
# independent - chat - window div : : - webkit - scrollbar - thumb {
background : # ddd ;
border - radius : 2 px ;
}
< / style >