feat: 抖音小程序开发

This commit is contained in:
2026-01-19 17:31:14 +08:00
parent 5d6db862ee
commit 388b1d1754
15 changed files with 216 additions and 113 deletions

View File

@@ -13,7 +13,25 @@
"ipLargeImageStep": 147,
"ipSmallImageStep": 117,
"ipLargeTime": 4,
"ipSmallTime": 4
"ipSmallTime": 4,
"grantType": "wechat"
},
"zhinianDY": {
"clientId": "7",
"appId": "wx5e79df5996572539",
"name": "智念",
"placeholder": "快告诉智念您在想什么~",
"loginDesc": "您好,欢迎来到智念科技",
"logo": "https://oss.nianxx.cn/mp/static/version_101/login/dh_logo.png",
"ipLargeImage": "https://oss.nianxx.cn/mp/static/version_101/dh/dh_large.png",
"ipSmallImage": "https://oss.nianxx.cn/mp/static/version_101/dh/dh_small.png",
"ipLargeImageHeight": 19687,
"ipSmallImageHeight": 3744,
"ipLargeImageStep": 147,
"ipSmallImageStep": 117,
"ipLargeTime": 4,
"ipSmallTime": 4,
"grantType": "douyin"
},
"duohua": {
"clientId": "2",
@@ -29,7 +47,8 @@
"ipLargeImageStep": 147,
"ipSmallImageStep": 117,
"ipLargeTime": 4,
"ipSmallTime": 4
"ipSmallTime": 4,
"grantType": "wechat"
},
"tianmu": {
"clientId": "4",
@@ -45,6 +64,24 @@
"ipLargeImageStep": 71,
"ipSmallImageStep": 148,
"ipLargeTime": 4,
"ipSmallTime": 6
"ipSmallTime": 6,
"grantType": "wechat"
},
"tianmuDY": {
"clientId": "7",
"appId": "wx0be424e1d22065a9",
"name": "沐沐",
"placeholder": "快告诉沐沐您在想什么~",
"loginDesc": "您好,欢迎来到天沐温泉",
"logo": "https://oss.nianxx.cn/mp/static/version_101/login/tm_logo.png",
"ipLargeImage": "https://oss.nianxx.cn/mp/static/version_101/tm/tm_large.png",
"ipSmallImage": "https://oss.nianxx.cn/mp/static/version_101/tm/tm_small.png",
"ipLargeImageHeight": 9514,
"ipSmallImageHeight": 4736,
"ipLargeImageStep": 71,
"ipSmallImageStep": 148,
"ipLargeTime": 4,
"ipSmallTime": 6,
"grantType": "douyin"
}
}

View File

@@ -1,5 +1,5 @@
{
"appid": "wx0be424e1d22065a9",
"appid": "wx5e79df5996572539",
"compileType": "miniprogram",
"libVersion": "3.8.10",
"packOptions": {

View File

@@ -67,7 +67,12 @@ const swipering = ref(false);
const animatingOut = ref(false);
let reorderTimer = null;
// #ifdef MP-TOUTIAO
const { windowWidth } = tt.getSystemInfoSync();
// #endif
// #ifdef MP-WEIXIN
const { windowWidth } = uni.getWindowInfo();
// #endif
let uidCounter = 0;
// 始终生成全局唯一的 __uid避免因重复 key 导致后续卡片无法正确重渲染与绑定事件

View File

@@ -1,37 +1,23 @@
<template>
<view :class="navBarClass" :style="navBarStyle">
<!-- 状态栏占位 -->
<view
:style="{ height: statusBarHeight + 'px' }"
v-if="!hideStatusBar"
></view>
<view :style="{ height: statusBarHeight + 'px' }" v-if="!hideStatusBar"></view>
<!-- 导航栏内容 -->
<view
class="flex flex-items-center flex-justify-between border-box pl-8 pr-8"
:style="{ height: navBarHeight + 'px' }"
>
<view class="flex flex-items-center flex-justify-between border-box pl-8 pr-8"
:style="{ height: navBarHeight + 'px' }">
<!-- 左侧返回按钮 -->
<view
class="nav-bar-left flex flex-items-center flex-justify-center"
v-if="showBack"
@click="handleBack"
>
<view class="nav-bar-left flex flex-items-center flex-justify-center" v-if="showBack" @click="handleBack">
<uni-icons type="left" size="20" :color="backIconColor" />
</view>
<!-- 中间标题区域 -->
<view
:class="[
'nav-bar-center flex flex-items-center flex-justify-center',
`nav-bar-center--${titleAlign}`,
]"
>
<view :class="[
'nav-bar-center flex flex-items-center flex-justify-center',
`nav-bar-center--${titleAlign}`,
]">
<slot name="title">
<text
class="font-size-17 font-500 color-000"
:style="{ color: titleColor }"
>
<text class="font-size-17 font-500 color-000" :style="{ color: titleColor }">
{{ title }}
</text>
</slot>
@@ -107,7 +93,13 @@ const navBarHeight = ref(44); // 默认导航栏高度
// 获取系统信息
onMounted(() => {
const systemInfo = uni.getSystemInfoSync();
// #ifdef MP-TOUTIAO
const systemInfo = tt.getSystemInfoSync();
// #endif
// #ifdef MP-WEIXIN
const systemInfo = uni.getWindowInfo();
// #endif
statusBarHeight.value = systemInfo.statusBarHeight || 0;
// 根据平台设置导航栏高度

View File

@@ -12,8 +12,9 @@ import rawConfigs from '../../client-configs.json' with { type: 'json' };
export const CLIENT_CONFIGS = rawConfigs;
// 获取当前用户端配置
export const getCurrentConfig = () => CLIENT_CONFIGS.tianmu;
export const getCurrentConfig = () => CLIENT_CONFIGS.zhinianDY;
export const clientId = getCurrentConfig().clientId;
export const grantType = getCurrentConfig().grantType;
export const appId = getCurrentConfig().appId;

View File

@@ -1,6 +1,6 @@
import { oauthToken, checkUserPhone } from "@/request/api/LoginApi";
import { loginAuth, bindPhone } from "@/manager/LoginManager";
import { clientId } from "@/constant/base";
import { clientId, grantType } from "@/constant/base";
import { getAccessToken, removeAccessToken, setAccessToken } from "../constant/token";
import { NOTICE_EVENT_LOGIN_SUCCESS } from "@/constant/constant";
@@ -70,35 +70,43 @@ export const checkToken = () => {
// 刷新token
export const refreshToken = () => {
return new Promise(async (resolve) => {
uni.login({
provider: "weixin", //使用微信登录
success: async ({ code }) => {
console.log("进入 refreshToken success", code);
const params = {
openIdCode: [code],
grant_type: "wechat",
scope: "server",
clientId: clientId,
};
console.log("获取到的微信授权params:", JSON.stringify(params));
uni.getProvider({
service: 'oauth',
success: function (res) {
// 获取客户端类型
console.log('获取客户端类型:', res.provider)
uni.login({
provider: res.provider, //使用微信登录
success: async ({ code }) => {
console.log("进入 refreshToken success code:", code);
// console.log("进入 refreshToken success anonymousCode:", anonymousCode);
const params = {
openIdCode: [code],
grant_type: grantType,
scope: "server",
clientId: clientId,
};
console.log("获取到的微信授权params:", JSON.stringify(params));
const response = await oauthToken(params);
if (response.access_token) {
setAccessToken(response.access_token);
const response = await oauthToken(params);
if (response.access_token) {
setAccessToken(response.access_token);
const checkRes = await checkUserPhone({
token: response.access_token,
});
const checkRes = await checkUserPhone({
token: response.access_token,
});
if (checkRes.data) {
// 登录成功后,触发登录成功事件
uni.$emit(NOTICE_EVENT_LOGIN_SUCCESS);
resolve(false);
} else {
resolve(true);
}
}
},
if (checkRes.data) {
// 登录成功后,触发登录成功事件
uni.$emit(NOTICE_EVENT_LOGIN_SUCCESS);
resolve(false);
} else {
resolve(true);
}
}
},
});
}
});
});
};

View File

@@ -60,7 +60,7 @@
wx23f86d809ae80259
*/
"mp-weixin": {
"appid": "wx0be424e1d22065a9",
"appid": "wx5e79df5996572539",
"setting": {
"urlCheck": false,
"minified": true

View File

@@ -16,10 +16,12 @@
<text class="amt font-size-18 font-500 font-family-misans-vf line-height-24 color-FF3D60 mr-4">
{{ item.specificationPrice }}
</text>
<!-- #ifdef MP-WEIXIN -->
<text class="font-size-12 line-height-16 color-99A0AE">
/{{ item.stockUnitLabel }}
</text>
<text class="btn border-box rounded-10 color-white ml-16" @click.stop="handleBooking(item)"></text>
<!-- #endif -->
</view>
</view>
</view>

View File

@@ -49,7 +49,7 @@
>
{{ calculatedTotalPrice }}
</view>
<!-- #ifdef MP-WEIXIN -->
<view
class="btn border-box rounded-10 flex flex-items-center ml-auto pl-8"
@click="navigateToPay(goodsData)"
@@ -60,8 +60,10 @@
/>
<text class="font-size-16 font-500 color-white">立即预定</text>
</view>
<!-- #endif -->
</view>
<!-- 日历组件 -->
<Calender
:visible="calendarVisible"

View File

@@ -180,6 +180,7 @@ const initRecord = () => {
// 监听键盘高度变化
onMounted(() => {
// 监听键盘弹起
// #ifdef MP-WEIXIN
uni.onKeyboardHeightChange((res) => {
keyboardHeight.value = res.height;
if (res.height) {
@@ -188,8 +189,8 @@ onMounted(() => {
emit("keyboardHide");
}
});
initRecord();
// #endif
});
const sendMessage = () => {

View File

@@ -296,11 +296,19 @@ const addNoticeListener = () => {
/// =============生命周期函数↓================
onLoad(() => {
uni.getSystemInfo({
success: (res) => {
statusBarHeight.value = res.statusBarHeight || 20;
},
});
console.log(21212121212)
nextTick(() => {
// #ifdef MP-TOUTIAO
const systemInfo = tt.getSystemInfoSync();
// #endif
// #ifdef MP-WEIXIN
const systemInfo = uni.getWindowInfo();
// #endif
statusBarHeight.value = systemInfo.statusBarHeight || 20;
console.log(1213213123, statusBarHeight.value, systemInfo.statusBarHeight)
})
});
// token存在初始化数据
@@ -662,31 +670,31 @@ const sendWebSocketMessage = async (messageType, messageContent, options = {}) =
try {
const raw = webSocketManager.sendMessage(args);
// 兼容可能返回同步布尔或 Promise 的实现
const result = await Promise.resolve(raw);
if (result) {
console.log(`WebSocket消息已发送 [类型:${messageType}]:`, args);
return true;
}
const result = await Promise.resolve(raw);
if (result) {
console.log(`WebSocket消息已发送 [类型:${messageType}]:`, args);
return true;
}
// 若返回 false消息可能已经被 manager 入队并触发连接流程。
// 在这种情况下避免立即当作失败处理,而是等待短暂时间以观察连接是否建立并由 manager 发送队列。
console.warn('webSocketManager.sendMessage 返回 false等待连接或队列发送...', { attempt, args });
const waitForConnectMs = typeof options.waitForConnectMs === 'number' ? options.waitForConnectMs : 5000;
if (webSocketManager && typeof webSocketManager.isConnected === 'function' && !webSocketManager.isConnected()) {
const startTs = Date.now();
while (Date.now() - startTs < waitForConnectMs) {
await sleep(200);
if (webSocketManager.isConnected()) {
// 给 manager 一点时间处理队列并发送
await sleep(150);
console.log('检测到 manager 已连接,假定队列消息已发送', args);
return true;
}
// 若返回 false消息可能已经被 manager 入队并触发连接流程。
// 在这种情况下避免立即当作失败处理,而是等待短暂时间以观察连接是否建立并由 manager 发送队列。
console.warn('webSocketManager.sendMessage 返回 false等待连接或队列发送...', { attempt, args });
const waitForConnectMs = typeof options.waitForConnectMs === 'number' ? options.waitForConnectMs : 5000;
if (webSocketManager && typeof webSocketManager.isConnected === 'function' && !webSocketManager.isConnected()) {
const startTs = Date.now();
while (Date.now() - startTs < waitForConnectMs) {
await sleep(200);
if (webSocketManager.isConnected()) {
// 给 manager 一点时间处理队列并发送
await sleep(150);
console.log('检测到 manager 已连接,假定队列消息已发送', args);
return true;
}
console.warn('等待 manager 建连超时,进入重试逻辑', { waitForConnectMs, args });
} else {
console.warn('sendMessage 返回 false 但 manager 看起来已连接或不可用,继续重试', { args });
}
console.warn('等待 manager 建连超时,进入重试逻辑', { waitForConnectMs, args });
} else {
console.warn('sendMessage 返回 false 但 manager 看起来已连接或不可用,继续重试', { args });
}
} catch (error) {
console.error('发送WebSocket消息异常:', error, args);
}
@@ -810,11 +818,11 @@ const stopRequest = async () => {
}
if (chatMsgList.value[aiMsgIndex] &&
chatMsgList.value[aiMsgIndex].msgType === MessageRole.AI) {
chatMsgList.value[aiMsgIndex].msgType === MessageRole.AI) {
chatMsgList.value[aiMsgIndex].isLoading = false;
if (chatMsgList.value[aiMsgIndex].msg &&
chatMsgList.value[aiMsgIndex].msg.trim() &&
!chatMsgList.value[aiMsgIndex].msg.startsWith("加载中")) {
chatMsgList.value[aiMsgIndex].msg.trim() &&
!chatMsgList.value[aiMsgIndex].msg.startsWith("加载中")) {
// 保留已显示内容
} else {
chatMsgList.value[aiMsgIndex].msg = "请求已停止";

View File

@@ -38,8 +38,9 @@
</button>
<!-- #endif -->
<!-- #ifdef MP-TOUTIAO -->
<button class="login-btn" type="primary" open-type="getPhoneNumber" bindgetphonenumber="getPhoneNumberHandler"
bindtap="bindPhone">登录</button>
<!-- <button class="login-btn" type="primary" open-type="getPhoneNumber" @getphonenumber="getPhoneNumberHandler"
@bindtap="bindPhone">登录</button> -->
<button class="login-btn" type="primary" @click="loginhandle">登录</button>
<!-- #endif -->
</view>
@@ -107,9 +108,13 @@ const getPhoneNumber = (e) => {
};
const getPhoneNumberHandler = (e) => {
console.log(e.detail.errMsg);
console.log(e.detail.iv);
console.log(e.detail.encryptedData);
console.log('getphonenumber:', e)
// console.log(e.detail.errMsg);
// console.log(e.detail.iv);
// console.log(e.detail.encryptedData);
}
const bindPhone = (e) => {
console.log('bindPhone:', e)
}
// 抖音登录获取code
@@ -188,10 +193,35 @@ getPrivacyAgreementData();
// 页面显示时刷新token
onShow(async () => {
loginDy();
// #ifdef MP-TOUTIAO
// loginDy();
// #endif
// #ifdef MP-WEIXIN
loginhandle();
// #endif
});
const loginhandle = async () => {
// 如果需要微信登录,直接返回
// #ifdef MP-TOUTIAO
if (!isAgree.value) {
uni.showToast({
title: "请先同意服务协议和隐私协议",
icon: "none",
});
return;
}
// #endif
const res = await refreshToken();
needWxAuthLogin.value = res;
});
// #ifdef MP-TOUTIAO
loginSuccess();
// #endif
};
</script>
@@ -203,4 +233,4 @@ onShow(async () => {
font-family: znicons;
src: url("@/static/fonts/znicons.ttf");
}
</style>
</style>

View File

@@ -151,7 +151,9 @@ export default {
},
mounted () {
this.$nextTick(() => {
for (this.root = this.$parent; this.root.$options.name !== 'mp-html'; this.root = this.root.$parent);
if (this.root) {
for (this.root = this.$parent; this.root.$options.name !== 'mp-html'; this.root = this.root.$parent);
}
})
// #ifdef H5 || APP-PLUS
if (this.opts[0]) {

View File

@@ -75,20 +75,33 @@ const config = {
foreignobject: 'foreignObject'
}
}
const tagSelector={}
const tagSelector = {}
let windowWidth, system
// #ifdef MP-TOUTIAO
const systemInfo = tt.getSystemInfoSync()
windowWidth = systemInfo.windowWidth
system = systemInfo.system
// #endif
// #ifdef MP-WEIXIN
windowWidth = uni.getWindowInfo().windowWidth
system = uni.getDeviceInfo().system
// #endif
if (uni.canIUse('getWindowInfo')) {
// #ifdef MP-WEIXIN
windowWidth = uni.getWindowInfo().windowWidth
system = uni.getDeviceInfo().system
// #endif
} else {
// #endif
// #ifdef MP-WEIXIN
const systemInfo = uni.getSystemInfoSync()
windowWidth = systemInfo.windowWidth
// #ifdef MP-WEIXIN
system = systemInfo.system
// #endif
}
// #endif
const blankChar = makeMap(' ,\r,\n,\t,\f')
let idIndex = 0
@@ -107,7 +120,7 @@ config.ignoreTags.style = undefined
* @description 创建 map
* @param {String} str 逗号分隔
*/
function makeMap (str) {
function makeMap(str) {
const map = Object.create(null)
const list = str.split(',')
for (let i = list.length; i--;) {
@@ -122,7 +135,7 @@ function makeMap (str) {
* @param {Boolean} amp 要不要解码 &amp;
* @returns {String} 解码后的字符串
*/
function decodeEntity (str, amp) {
function decodeEntity(str, amp) {
let i = str.indexOf('&')
while (i !== -1) {
const j = str.indexOf(';', i + 3)
@@ -150,7 +163,7 @@ function decodeEntity (str, amp) {
* @description 合并多个块级标签,加快长内容渲染
* @param {Array} nodes 要合并的标签数组
*/
function mergeNodes (nodes) {
function mergeNodes(nodes) {
let i = nodes.length - 1
for (let j = i; j >= -1; j--) {
if (j === -1 || nodes[j].c || !nodes[j].name || (nodes[j].name !== 'div' && nodes[j].name !== 'p' && nodes[j].name[0] !== 'h') || (nodes[j].attrs.style || '').includes('inline')) {
@@ -170,7 +183,7 @@ function mergeNodes (nodes) {
* @description html 解析器
* @param {Object} vm 组件实例
*/
function Parser (vm) {
function Parser(vm) {
this.options = vm || {}
this.tagStyle = Object.assign({}, config.tagStyle, this.options.tagStyle)
this.imgList = vm.imgList || []
@@ -672,7 +685,7 @@ Parser.prototype.popNode = function () {
return
}
// #ifdef APP-PLUS-NVUE
(function traversal (node) {
(function traversal(node) {
if (node.name) {
// 调整 svg 的大小写
node.name = config.svgDict[node.name] || node.name
@@ -693,7 +706,7 @@ Parser.prototype.popNode = function () {
const style = attrs.style
attrs.style = ''
attrs.xmlns = 'http://www.w3.org/2000/svg';
(function traversal (node) {
(function traversal(node) {
if (node.type === 'text') {
src += node.text
return
@@ -887,7 +900,7 @@ Parser.prototype.popNode = function () {
const cells = [] // 保存新的单元格
const map = {}; // 被合并单元格占用的格子
(function traversal (nodes) {
(function traversal(nodes) {
for (let i = 0; i < nodes.length; i++) {
if (nodes[i].name === 'tr') {
trList.push(nodes[i])
@@ -1007,7 +1020,7 @@ Parser.prototype.popNode = function () {
}
if (border || padding) {
// 遍历
(function traversal (nodes) {
(function traversal(nodes) {
for (let i = 0; i < nodes.length; i++) {
const td = nodes[i]
if (td.name === 'th' || td.name === 'td') {
@@ -1036,7 +1049,7 @@ Parser.prototype.popNode = function () {
}
} else if ((node.name === 'tbody' || node.name === 'tr') && node.flag && node.c) {
node.flag = undefined;
(function traversal (nodes) {
(function traversal(nodes) {
for (let i = 0; i < nodes.length; i++) {
if (nodes[i].name === 'td') {
// 颜色样式设置给单元格避免丢失
@@ -1078,7 +1091,7 @@ Parser.prototype.popNode = function () {
}
}
} else if (node.c) {
(function traversal (node) {
(function traversal(node) {
node.c = 2
for (let i = node.children.length; i--;) {
const child = node.children[i]
@@ -1199,7 +1212,7 @@ Parser.prototype.onText = function (text) {
* @description html 词法分析器
* @param {Object} handler 高层处理器
*/
function Lexer (handler) {
function Lexer(handler) {
this.handler = handler
}

View File

@@ -8,7 +8,9 @@ export default {
if (allowShare) {
uni.showShareMenu({
withShareTicket: true,
// #ifdef MP-WEIXIN
menus: ["shareAppMessage", "shareTimeline"],
// #endif
});
}
},