feat(global): 国际化及配置处理

This commit is contained in:
woody 2025-08-28 10:54:21 +08:00
parent 65a6780398
commit 9453a799b7
21 changed files with 505 additions and 3117 deletions

View File

@ -221,12 +221,7 @@ export default {
this.$i18n.mergeLocaleMessage(name, enUS); this.$i18n.mergeLocaleMessage(name, enUS);
} }
} }
if (name == "ru-RU") {
if (ruRU) {
const localruRU = this.getJS(ruRU, "ruRU");
this.$i18n.mergeLocaleMessage(name, ruRU);
}
}
if (name == "fr-FR") { if (name == "fr-FR") {
if (frFR) { if (frFR) {
const localruRU = this.getJS(frFR, "frFR"); const localruRU = this.getJS(frFR, "frFR");
@ -238,9 +233,7 @@ export default {
let self = this; let self = this;
self.setLocale("en-US", "enUS", "en"); self.setLocale("en-US", "enUS", "en");
self.setLocale("zh-CN", "zhCN", "zh-CN"); self.setLocale("zh-CN", "zhCN", "zh-CN");
self.setLocale("ru-RU", "ruRU", "ru-RU");
self.setLocale("fr-FR", "frFR", "fr-FR"); self.setLocale("fr-FR", "frFR", "fr-FR");
// self.setLocale('pt-PT', 'ptPT', 'pt-PT');
}, },
isFirstEnter() { isFirstEnter() {
var firstEnter = uni.getStorageSync("firstEnter"); // var firstEnter = uni.getStorageSync("firstEnter"); //

View File

@ -130,7 +130,7 @@
}, },
getData() { getData() {
let self = this; let self = this;
self._get("/member/api/member/get-member-annuity-time", {}, (res) => { self._get("member/api/member/get-member-annuity-time", {}, (res) => {
self.annuityParams = res.data; self.annuityParams = res.data;
if ( if (
self.annuityParams.expireDateNumber <= 60 && self.annuityParams.expireDateNumber <= 60 &&
@ -146,7 +146,7 @@
}, },
getMemberRenewAmount() { getMemberRenewAmount() {
let self = this; let self = this;
self._get("/member/api/member/get-member-renew-amount", {}, (res) => { self._get("member/api/member/get-member-renew-amount", {}, (res) => {
this.qnnuityPrice = res.data; this.qnnuityPrice = res.data;
this.isPopup = true; this.isPopup = true;
}); });

View File

@ -42,14 +42,6 @@
></image> ></image>
</view> </view>
<view> <view>
<!-- <image
crossorigin="anonymous"
data-etype="image"
:data-enode="treeData.countryUrl2"
:src="'data:image/png;base64,' + treeData.countryUrl2Base64"
mode="aspectFit"
class="poster2"
></image> -->
<image <image
crossorigin="anonymous" crossorigin="anonymous"
data-etype="image" data-etype="image"
@ -139,7 +131,6 @@
</view> </view>
</view> </view>
<view class="flex_btn"> <view class="flex_btn">
<!-- <view @click.stop="downImage('Poster1')" class="goTop_btn" style="backgroundColor:#ee1e26">{{ $t('S_C_45') }}</view> -->
<view <view
@click.stop="copyText(treeData)" @click.stop="copyText(treeData)"
class="goTop_btn" class="goTop_btn"
@ -164,8 +155,7 @@
v-if=" v-if="
Array.isArray(treeData.children) && Array.isArray(treeData.children) &&
treeData.children.length && treeData.children.length &&
treeData.extend && treeData.extend
!loading
" "
> >
<view <view
@ -175,7 +165,7 @@
class="childLevel v-td" class="childLevel v-td"
> >
<TreeChart <TreeChart
:json="children" :treeData="children"
:left="0" :left="0"
:top="0" :top="0"
@click-node="clickNode" @click-node="clickNode"
@ -183,7 +173,6 @@
/> />
</view> </view>
</view> </view>
<!-- <Eposter width="750" height="1334" :list="list" backgroundColor="rgb(255, 255, 255)" @on-success="onSuccess" ref="Eposter"></Eposter> -->
</view> </view>
</template> </template>
@ -195,59 +184,14 @@ export default {
// Eposter // Eposter
}, },
name: "TreeChart", name: "TreeChart",
props: ["json", "size"], props: ["treeData", "size"],
data() { data() {
return { return {
treeData: {},
list: [], list: [],
languages: "", languages: "",
loading: true,
}; };
}, },
watch: {
json: {
handler: function (Props) {
let extendKey = function (jsonData) {
if (Object.prototype.toString.call(jsonData) !== "[object Object]") {
jsonData = {};
}
jsonData.extend =
jsonData.extend === void 0 ? true : !!jsonData.extend;
if (Array.isArray(jsonData.children)) {
jsonData.children.forEach((c) => {
extendKey(c);
});
}
return jsonData;
};
if (Props) {
let self = this;
// self._post(
// 'member/manage/member-structure/get-url-base64',
// {
// countryUrl2: extendKey(Props).countryUrl2,
// settleCountryUrl2: extendKey(Props).settleCountryUrl2,
// avatarUrl: extendKey(Props).avatarUrl
// },
// res => {
// extendKey(Props).countryUrl2Base64 = res.countryUrl2Base64;
// extendKey(Props).settleCountryUrl2Base64 = res.settleCountryUrl2Base64;
// extendKey(Props).avatarUrlBase64 = res.avatarUrlBase64;
// this.treeData = extendKey(Props);
// self.loading = false;
// }
// );
extendKey(Props).countryUrl2Base64 = extendKey(Props).countryUrl2;
extendKey(Props).settleCountryUrl2Base64 =
extendKey(Props).settleCountryUrl2;
extendKey(Props).avatarUrlBase64 = extendKey(Props).avatarUrl;
this.treeData = extendKey(Props);
self.loading = false;
}
},
immediate: true,
},
},
onload() { onload() {
this.languages = uni.getLocale(); this.languages = uni.getLocale();
}, },
@ -291,44 +235,6 @@ export default {
}, },
}); });
}, },
//
downImage(elClass) {
this.$refs.Eposter.createForElRect(elClass, false);
},
downloadImg() {
let self = this;
let element = document.querySelector(".Poster1");
uni.showLoading({
title: self.$t("w_0413"),
});
html2canvas(element)
.then(function (canvas) {
let dataURL = canvas.toDataURL("image/jpeg");
let link = document.createElement("a");
link.style.display = "none";
link.href = dataURL;
link.download = "image.jpg";
document.body.appendChild(link);
link.click();
document.body.removeChild(link);
uni.showToast({
icon: "none",
title: self.$t("fn_056"),
duration: 2000,
});
uni.hideLoading();
})
.catch(function (error) {
uni.hideLoading();
uni.showModal({
title: self.$t("w_0406"),
});
});
},
onSuccess(val) {
this.posterImg = val;
this.downloadImg(this.posterImg);
},
toggleExtend: function (treeData) { toggleExtend: function (treeData) {
treeData.extend = !treeData.extend; treeData.extend = !treeData.extend;
this.$forceUpdate(); this.$forceUpdate();

View File

@ -1,14 +1,12 @@
var app_url = 'http://f.hzs413.com'; var app_url = '/prod-api';
var yxyapi = 'https://yxy.hzs413.com'; var yxyapi = 'https://yxy.hzs413.com';
var ossapi = 'https://dny-test.s3.ap-southeast-1.amazonaws.com'; var ossapi = 'https://bd-qd.oss-cn-beijing.aliyuncs.com';
var ossurl = '/online/language/'; var ossurl = '/test_africa/language/';
// 如果是本地测试环境 // 如果是本地测试环境
if (process.env.NODE_ENV === 'development') { if (process.env.NODE_ENV === 'development') {
//#ifdef H5 //#ifdef H5
app_url = '/api'; app_url = 'http://192.168.0.86:8080/';
yxyapi = '/dev-api'; yxyapi = '/dev-api';
ossapi = '/oss-api';
ossurl = '/online/language/';
//#endif //#endif
} }
// 如果是生产环境h5环境下直接读取url // 如果是生产环境h5环境下直接读取url

View File

@ -2,14 +2,12 @@ import enUS from './en-US.json'
import zhCN from './zh-CN'; import zhCN from './zh-CN';
// import zhHant from './zh-Hant.json' // import zhHant from './zh-Hant.json'
import frFR from './fr-FR.json' import frFR from './fr-FR.json'
import ruRU from './ru-RU.json'
import ptPT from './pt-PT.json' import ptPT from './pt-PT.json'
export default { export default {
'en-US': enUS, 'en-US': enUS,
'zh-CN': zhCN, 'zh-CN': zhCN,
// 'zh-Hant': zhHant, // 'zh-Hant': zhHant,
'fr-FR': frFR, 'fr-FR': frFR,
'ru-RU': ruRU,
'pt-PT':ptPT 'pt-PT':ptPT
} }

File diff suppressed because it is too large Load Diff

View File

@ -1,34 +0,0 @@
{
"common": {
"uni.app.quit": "Нажмите еще раз, чтобы выйти из приложения",
"uni.async.error": "Время ожидания подключения к серверу, нажмите на экран, чтобы повторить попытку",
"uni.showActionSheet.cancel": "Отменить",
"uni.showToast.unpaired": "Обратите внимание, что ShowToast и HideToast должны работать вместе.",
"uni.showLoading.unpaired": "Обратите внимание, что showLoading и hideLoading должны быть совместимы.",
"uni.showModal.cancel": "Отменить",
"uni.showModal.confirm": "Определение",
"uni.chooseImage.cancel": "Отменить",
"uni.chooseImage.sourceType.album": "Выбрать из альбома",
"uni.chooseImage.sourceType.camera": "Съемки",
"uni.chooseVideo.cancel": "Отменить",
"uni.chooseVideo.sourceType.album": "Выбрать из альбома",
"uni.chooseVideo.sourceType.camera": "Съемки",
"uni.previewImage.cancel": "Отменить",
"uni.previewImage.button.save": "Сохранить изображение",
"uni.previewImage.save.success": "Сохранить изображение в альбом",
"uni.previewImage.save.fail": "Ошибка сохранения изображения в альбоме",
"uni.setClipboardData.success": "Содержание скопировано",
"uni.scanCode.title": "Код сканирования",
"uni.scanCode.album": "Фотоальбом",
"uni.scanCode.fail": "Ошибка идентификации",
"uni.scanCode.flash.on": "Подсветка",
"uni.scanCode.flash.off": "Приключения закрываются",
"uni.startSoterAuthentication.authContent": "Отпечатки пальцев....",
"uni.picker.done": "Завершено",
"uni.picker.cancel": "Отменить",
"uni.video.danmu": "Снаряд",
"uni.video.volume": "Громкость",
"uni.button.feedback.title": "Обратная связь ",
"uni.button.feedback.send": "Отправить"
}
}

23
main.js
View File

@ -17,14 +17,9 @@ let i18nConfig = {
'en-US': messages['en-US'], 'en-US': messages['en-US'],
'zh-CN': messages['zh-CN'], 'zh-CN': messages['zh-CN'],
// 'zh-Hant': messages['zh-Hant'], // 'zh-Hant': messages['zh-Hant'],
'ru-RU': messages['ru-RU'],
'fr-FR': messages['fr-FR'], 'fr-FR': messages['fr-FR'],
'pt-PT': messages['pt-PT'], 'pt-PT': messages['pt-PT'],
// 'en': '',
// 'zh-CN': '',
// 'zh-Hant': '',
// 'ru-RU': '',
// 'fr-FR': '',
} }
} }
import VueI18n from 'vue-i18n' import VueI18n from 'vue-i18n'
@ -114,10 +109,12 @@ Vue.prototype._get = function(path, data, success, fail, complete) {
let host = self.websiteUrl(); let host = self.websiteUrl();
// #ifndef APP-PLUS // #ifndef APP-PLUS
host = config.app_url host = config.app_url
console.log(host, '...host')
// #endif // #endif
let callback = function() { let callback = function() {
uni.request({ uni.request({
url: '/prod-api/' + path, url: host + path,
data: data, data: data,
dataType: 'json', dataType: 'json',
header: { header: {
@ -195,7 +192,7 @@ Vue.prototype._post = function(path, data, success, fail, complete) {
Source = '3' Source = '3'
// #endif // #endif
uni.request({ uni.request({
url: '/prod-api/' + path, url: host + path,
data: data, data: data,
dataType: 'json', dataType: 'json',
method: 'POST', method: 'POST',
@ -241,7 +238,7 @@ Vue.prototype._put = function(path, data, success, fail, complete) {
host = config.app_url host = config.app_url
// #endif // #endif
uni.request({ uni.request({
url: '/prod-api/' + path + '/' + data, url: host + path + '/' + data,
dataType: 'json', dataType: 'json',
method: 'PUT', method: 'PUT',
header: { header: {
@ -281,7 +278,7 @@ Vue.prototype._putjson = function(path, data, success, fail, complete) {
host = config.app_url host = config.app_url
// #endif // #endif
uni.request({ uni.request({
url: '/prod-api/' + path, url: host + path,
data: data, data: data,
dataType: 'json', dataType: 'json',
method: 'PUT', method: 'PUT',
@ -321,7 +318,7 @@ Vue.prototype._delete = function(path, data, success, fail, complete) {
host = config.app_url host = config.app_url
// #endif // #endif
uni.request({ uni.request({
url: '/prod-api/' + path, url: host + path,
dataType: 'json', dataType: 'json',
method: 'DELETE', method: 'DELETE',
header: { header: {
@ -698,8 +695,6 @@ Vue.prototype.getLocale = function() {
return 'zh-TC' return 'zh-TC'
} else if (l == 'fr-FR') { } else if (l == 'fr-FR') {
return 'fr-FR' return 'fr-FR'
} else if (l == 'ru-RU') {
return 'ru-RU'
} else if (l == 'pt-PT') { } else if (l == 'pt-PT') {
return 'pt-PT' return 'pt-PT'
} else { } else {
@ -714,8 +709,6 @@ Vue.prototype.getLanguage = function() {
return 'zh-TC' return 'zh-TC'
} else if (l == 'fr-FR') { } else if (l == 'fr-FR') {
return 'fr-FR' return 'fr-FR'
} else if (l == 'ru-RU') {
return 'ru-RU'
} else if (l == 'pt-PT') { } else if (l == 'pt-PT') {
return 'pt-PT' return 'pt-PT'
} else { } else {

View File

@ -168,14 +168,11 @@
"devServer": { "devServer": {
"https": false, "https": false,
"proxy": { "proxy": {
"/api": { "/prod-api": {
"ws": false, "ws": false,
"target": "http://f.hzs413.com", "target": "http://af-app.beida413.com/",
"changeOrigin": true, "changeOrigin": true,
"secure": false, "secure": false
"pathRewrite": {
"^/api": "/"
}
}, },
"/dev-api": { "/dev-api": {
"ws": false, "ws": false,

View File

@ -162,7 +162,7 @@ export default {
getDataList() { getDataList() {
let self = this; let self = this;
let params = this.queryParams; let params = this.queryParams;
self._get("/member/api/member-structure/tj-framework", params, (res) => { self._get("member/api/member-structure/tj-framework", params, (res) => {
self.treeData = res.data; self.treeData = res.data;
}); });
}, },

View File

@ -0,0 +1,30 @@
export default {
data() {
return {
archTreeData: {},
};
},
methods: {
archDataFormat(archTreeData) {
const forkData = JSON.parse(JSON.stringify(archTreeData))
const addExtendKey = (forkData) => {
if (!forkData) {
forkData = {}
}
forkData.extend = forkData.extend === void 0 ? true : !!forkData.extend
if (Array.isArray(forkData.children)) {
forkData.children.forEach((c) => {
addExtendKey(c)
})
} else {
forkData.countryUrl2Base64 = forkData.countryUrl2
forkData.settleCountryUrl2Base64 = forkData.settleCountryUrl2
forkData.avatarUrlBase64 = forkData.avatarUrl
}
return forkData
}
addExtendKey(forkData)
return forkData
},
},
};

View File

@ -0,0 +1,425 @@
// 兼容性处理requestAnimationFrame polyfill
const getRequestAnimationFrame = () => {
// 检查全局对象是否存在uni-app 中可能是 uni 而不是 window
const global = typeof window !== 'undefined' ? window :
typeof uni !== 'undefined' ? uni :
typeof global !== 'undefined' ? global : {};
return global.requestAnimationFrame ||
global.webkitRequestAnimationFrame ||
global.mozRequestAnimationFrame ||
global.oRequestAnimationFrame ||
global.msRequestAnimationFrame ||
function(callback) {
return setTimeout(callback, 1000 / 60); // 60 FPS fallback
};
};
const getCancelAnimationFrame = () => {
const global = typeof window !== 'undefined' ? window :
typeof uni !== 'undefined' ? uni :
typeof global !== 'undefined' ? global : {};
return global.cancelAnimationFrame ||
global.webkitCancelAnimationFrame ||
global.mozCancelAnimationFrame ||
global.oCancelAnimationFrame ||
global.msCancelAnimationFrame ||
function(id) {
return clearTimeout(id);
};
};
const requestAnimationFrame = getRequestAnimationFrame();
const cancelAnimationFrame = getCancelAnimationFrame();
export default {
data() {
return {
// 触摸缩放相关状态
touchStartPosition1: {
x: 0,
y: 0,
},
touchStartPosition2: {
x: 0,
y: 0,
},
initialDistance: 0,
x: 0, // 元素的x坐标
y: 0, // 元素的y坐标
scale: 1, // 元素的缩放比例
initialX: 0, // 元素的初始x坐标
initialY: 0, // 元素的初始y坐标
minScale: 0.5, // 最小缩放比例
maxScale: 3, // 最大缩放比例
isScaling: false, // 是否正在缩放
lastTouchTime: 0, // 上次触摸时间
// 拖拽优化相关
isDragging: false, // 是否正在拖拽
dragStartTime: 0, // 拖拽开始时间
lastMoveTime: 0, // 上次移动时间
velocity: { x: 0, y: 0 }, // 移动速度
animationId: null, // 动画帧ID
pendingUpdate: false, // 是否有待处理的更新
// 边界控制
enableBoundary: false, // 是否启用边界控制
boundary: {
minX: -500,
maxX: 500,
minY: -500,
maxY: 500,
}, // 移动边界
// 兼容性相关
useTimer: false, // 是否使用定时器代替 RAF兼容性降级
};
},
methods: {
/**
* 触摸开始事件处理
* @param {TouchEvent} event 触摸事件
*/
handleTouchStart(event) {
event.preventDefault();
// 取消之前的动画
if (this.animationId) {
this.safeCancelAnimationFrame(this.animationId);
this.animationId = null;
}
const currentTime = Date.now();
this.lastTouchTime = currentTime;
if (event.touches.length === 1) {
// 单指拖拽初始化
this.isScaling = false;
this.isDragging = true;
this.dragStartTime = currentTime;
this.lastMoveTime = currentTime;
this.initialX = event.touches[0].clientX;
this.initialY = event.touches[0].clientY;
this.velocity = { x: 0, y: 0 };
this.pendingUpdate = false;
} else if (event.touches.length === 2) {
// 双指缩放初始化
this.isScaling = true;
this.isDragging = false;
this.touchStartPosition1.x = event.touches[0].clientX;
this.touchStartPosition1.y = event.touches[0].clientY;
this.touchStartPosition2.x = event.touches[1].clientX;
this.touchStartPosition2.y = event.touches[1].clientY;
// 计算初始两指间距离
this.initialDistance = this.getDistance(
this.touchStartPosition1,
this.touchStartPosition2
);
}
},
/**
* 触摸移动事件处理
* @param {TouchEvent} event 触摸事件
*/
handleTouchMove(event) {
event.preventDefault();
if (event.touches.length === 2 && this.isScaling) {
// 双指缩放逻辑
const currentDistance = this.getDistance(
{ x: event.touches[0].clientX, y: event.touches[0].clientY },
{ x: event.touches[1].clientX, y: event.touches[1].clientY }
);
if (this.initialDistance > 0) {
// 计算缩放比例变化
const scaleChange = currentDistance / this.initialDistance;
let newScale = this.scale * scaleChange;
// 限制缩放范围
newScale = Math.max(this.minScale, Math.min(this.maxScale, newScale));
this.scale = newScale;
// 更新初始距离为当前距离,用于下次计算
this.initialDistance = currentDistance;
}
} else if (event.touches.length === 1 && this.isDragging) {
// 单指拖拽逻辑优化
const currentTime = Date.now();
const currentX = event.touches[0].clientX;
const currentY = event.touches[0].clientY;
// 计算移动距离
const deltaX = currentX - this.initialX;
const deltaY = currentY - this.initialY;
// 计算移动速度(用于惯性效果)
const timeDelta = currentTime - this.lastMoveTime;
if (timeDelta > 0) {
this.velocity.x = deltaX / timeDelta * 16; // 标准化到16ms60fps
this.velocity.y = deltaY / timeDelta * 16;
}
// 使用节流机制更新位置
this.schedulePositionUpdate(deltaX, deltaY);
// 更新初始位置和时间
this.initialX = currentX;
this.initialY = currentY;
this.lastMoveTime = currentTime;
}
},
/**
* 触摸结束事件处理
* @param {TouchEvent} event 触摸事件
*/
handleTouchEnd(event) {
if (event.touches.length === 0) {
// 所有手指都离开屏幕,重置状态
this.isScaling = false;
this.initialDistance = 0;
// 如果是拖拽结束,启动惯性效果
if (this.isDragging) {
this.isDragging = false;
this.startInertiaAnimation();
}
} else if (event.touches.length === 1 && this.isScaling) {
// 从双指变为单指,切换到拖拽模式
this.isScaling = false;
this.isDragging = true;
this.initialX = event.touches[0].clientX;
this.initialY = event.touches[0].clientY;
this.lastMoveTime = Date.now();
}
},
/**
* 计算两点间距离的辅助方法
* @param {Object} point1 第一个点 {x, y}
* @param {Object} point2 第二个点 {x, y}
* @return {Number} 两点间距离
*/
getDistance(point1, point2) {
const dx = point1.x - point2.x;
const dy = point1.y - point2.y;
return Math.sqrt(dx * dx + dy * dy);
},
/**
* 重置缩放和位置
*/
resetTransform() {
this.x = 0;
this.y = 0;
this.scale = 1;
this.isScaling = false;
this.initialDistance = 0;
},
/**
* 安全的 requestAnimationFrame 调用
* @param {Function} callback 回调函数
* @return {Number} 动画ID
*/
safeRequestAnimationFrame(callback) {
try {
if (this.useTimer) {
return setTimeout(callback, 16); // 约 60 FPS
}
return requestAnimationFrame(callback);
} catch (error) {
console.warn('requestAnimationFrame failed, fallback to setTimeout:', error);
this.useTimer = true;
return setTimeout(callback, 16);
}
},
/**
* 安全的 cancelAnimationFrame 调用
* @param {Number} id 动画ID
*/
safeCancelAnimationFrame(id) {
try {
if (this.useTimer || typeof id === 'number') {
clearTimeout(id);
} else {
cancelAnimationFrame(id);
}
} catch (error) {
console.warn('cancelAnimationFrame failed, fallback to clearTimeout:', error);
clearTimeout(id);
}
},
/**
* 节流位置更新机制
* @param {Number} deltaX x轴位移
* @param {Number} deltaY y轴位移
*/
schedulePositionUpdate(deltaX, deltaY) {
// 计算新位置
let newX = this.x + deltaX;
let newY = this.y + deltaY;
// 应用边界限制
if (this.enableBoundary) {
const pos = this.applyBoundaryConstraints(newX, newY);
newX = pos.x;
newY = pos.y;
}
// 更新位置
this.x = newX;
this.y = newY;
if (!this.pendingUpdate) {
this.pendingUpdate = true;
this.safeRequestAnimationFrame(() => {
this.pendingUpdate = false;
});
}
},
/**
* 启动惯性动画
*/
startInertiaAnimation() {
const minVelocity = 0.1; // 最小速度阈值
const friction = 0.95; // 摩擦系数
// 如果速度太小,直接停止
if (Math.abs(this.velocity.x) < minVelocity && Math.abs(this.velocity.y) < minVelocity) {
return;
}
const animate = () => {
// 应用摩擦力
this.velocity.x *= friction;
this.velocity.y *= friction;
// 更新位置
let newX = this.x + this.velocity.x;
let newY = this.y + this.velocity.y;
// 应用边界限制
if (this.enableBoundary) {
const pos = this.applyBoundaryConstraints(newX, newY);
newX = pos.x;
newY = pos.y;
// 如果到达边界,减慢对应方向的速度
if (newX !== this.x + this.velocity.x) {
this.velocity.x *= 0.3;
}
if (newY !== this.y + this.velocity.y) {
this.velocity.y *= 0.3;
}
}
this.x = newX;
this.y = newY;
// 检查是否继续动画
if (Math.abs(this.velocity.x) > minVelocity || Math.abs(this.velocity.y) > minVelocity) {
this.animationId = this.safeRequestAnimationFrame(animate);
} else {
this.animationId = null;
this.velocity = { x: 0, y: 0 };
}
};
this.animationId = this.safeRequestAnimationFrame(animate);
},
/**
* 应用边界约束
* @param {Number} x x坐标
* @param {Number} y y坐标
* @return {Object} 约束后的坐标 {x, y}
*/
applyBoundaryConstraints(x, y) {
return {
x: Math.max(this.boundary.minX, Math.min(this.boundary.maxX, x)),
y: Math.max(this.boundary.minY, Math.min(this.boundary.maxY, y)),
};
},
/**
* 设置缩放范围
* @param {Number} minScale 最小缩放比例
* @param {Number} maxScale 最大缩放比例
*/
setScaleRange(minScale, maxScale) {
this.minScale = minScale || 0.5;
this.maxScale = maxScale || 3;
},
/**
* 设置移动边界
* @param {Object} boundary 边界配置 {minX, maxX, minY, maxY}
* @param {Boolean} enable 是否启用边界控制
*/
setBoundary(boundary, enable = true) {
this.boundary = { ...this.boundary, ...boundary };
this.enableBoundary = enable;
},
/**
* 检测并设置兼容性模式
*/
detectCompatibility() {
try {
// 尝试调用 requestAnimationFrame
const testId = requestAnimationFrame(() => {});
cancelAnimationFrame(testId);
this.useTimer = false;
} catch (error) {
console.warn('requestAnimationFrame not supported, using timer fallback');
this.useTimer = true;
}
},
/**
* 强制使用定时器模式用于调试或特殊需求
* @param {Boolean} useTimer 是否使用定时器
*/
setTimerMode(useTimer = true) {
this.useTimer = useTimer;
if (useTimer) {
console.info('TouchScale: 已切换到定时器模式');
} else {
console.info('TouchScale: 已切换到 requestAnimationFrame 模式');
}
},
/**
* 清理动画和状态
*/
cleanupTouchScale() {
if (this.animationId) {
this.safeCancelAnimationFrame(this.animationId);
this.animationId = null;
}
this.isDragging = false;
this.isScaling = false;
this.velocity = { x: 0, y: 0 };
this.pendingUpdate = false;
},
},
// 组件创建时检测兼容性
mounted() {
this.detectCompatibility();
},
// 组件销毁时清理
beforeDestroy() {
this.cleanupTouchScale();
},
};

View File

@ -45,7 +45,7 @@
transform: `scale(${scale})`, transform: `scale(${scale})`,
}" }"
:size="size" :size="size"
:json="data" :treeData="archTreeData"
:class="{ landscape: landscape.length }" :class="{ landscape: landscape.length }"
@click-node="clickNode" @click-node="clickNode"
@click-top="clickTop" @click-top="clickTop"
@ -146,11 +146,14 @@
import html2canvas from "html2canvas"; import html2canvas from "html2canvas";
import TreeChart3 from "@/components/architectures/resettleSO1.vue"; import TreeChart3 from "@/components/architectures/resettleSO1.vue";
import Eposter from "@/components/architectures/Poster.vue"; import Eposter from "@/components/architectures/Poster.vue";
import archDataMixin from "./mixin/archDataMixin";
import touchScaleMixin from "./mixin/touchScaleMixin";
export default { export default {
components: { components: {
TreeChart3, TreeChart3,
Eposter, Eposter,
}, },
mixins: [archDataMixin, touchScaleMixin],
data() { data() {
return { return {
avaerInfoList: [], avaerInfoList: [],
@ -158,35 +161,21 @@ export default {
queryParams: { queryParams: {
memberSettlePeriodId: "", // memberSettlePeriodId: "", //
memberCode: "", // memberCode: "", //
level: 3, // level: 7, //
type: 1, type: 1,
}, },
memberSettlePeriodList: [], // memberSettlePeriodList: [], //
popShow: false, popShow: false,
listShow: false, listShow: false,
settleName: "", settleName: "",
data: {}, archTreeData: {},
size: 0.8, size: 0.8,
landscape: [], landscape: [],
popMould: {}, popMould: {},
isPop: false, isPop: false,
touchStartPosition1: {
x: 0,
y: 0,
},
touchStartPosition2: {
x: 0,
y: 0,
},
initialDistance: 0,
list: [], list: [],
startX: 0, startX: 0,
startY: 0, startY: 0
x: 0, // x
y: 0, // y
scale: 1, //
initialX: 0, // x
initialY: 0, // y
}; };
}, },
onLoad() { onLoad() {
@ -198,41 +187,8 @@ export default {
methods: { methods: {
onpenPop() { onpenPop() {
this.popShow = true; this.popShow = true;
console.log(this.popShow);
}, },
handleTouchStart(event) {
//
this.initialX = event.changedTouches[0].clientX;
this.initialY = event.changedTouches[0].clientY;
},
handleTouchMove(event) {
if (event.touches.length === 2) {
//
const deltaX = event.touches[0].clientX - event.touches[1].clientX;
const deltaY = event.touches[0].clientY - event.touches[1].clientY;
//
this.x += deltaX;
this.y += deltaY;
//
this.scale += deltaY / 100;
} else {
//
const deltaX = event.changedTouches[0].clientX - this.initialX;
const deltaY = event.changedTouches[0].clientY - this.initialY;
//
this.x += deltaX;
this.y += deltaY;
}
//
this.initialX = event.touches[0].clientX;
this.initialY = event.touches[0].clientY;
},
handleTouchEnd(event) {
// 便使
this.initialX = event.changedTouches[0].clientX;
this.initialY = event.changedTouches[0].clientY;
},
clickNode(e) {}, clickNode(e) {},
clickTop(e) { clickTop(e) {
let that = this; let that = this;
@ -260,10 +216,9 @@ export default {
); );
}, },
getDataList() { getDataList() {
let self = this;
let params = this.queryParams; let params = this.queryParams;
self._get("/member/api/member-structure/az-framework-first", params, (res) => { this._get("/member/api/member-structure/az-framework-first", params, (res) => {
self.data = res.data[0]; this.archTreeData = this.archDataFormat(res.data[0] || {});
}); });
}, },
clearAll() { clearAll() {

View File

@ -318,7 +318,7 @@ export default {
console.log(self.typeIndex); console.log(self.typeIndex);
let specialArea = self.typeList[self.typeIndex].specialArea; let specialArea = self.typeList[self.typeIndex].specialArea;
self._get( self._get(
"/sale/api/shopping/getShopping", "sale/api/shopping/getShopping",
{ {
specialArea: specialArea, specialArea: specialArea,
}, },
@ -339,7 +339,7 @@ export default {
getType() { getType() {
let self = this; let self = this;
self.isInit = false; self.isInit = false;
self._get("/sale/api/shopping/getShopping", {}, (res) => { self._get("sale/api/shopping/getShopping", {}, (res) => {
self.typeList = res.data; self.typeList = res.data;
if (self.typeList && self.typeList.length > 0) { if (self.typeList && self.typeList.length > 0) {
self.listData = self.typeList[0].shoppingCartList; self.listData = self.typeList[0].shoppingCartList;

View File

@ -49,7 +49,7 @@
v-for="(item, index) in advertBannerList" :key="index"></view> v-for="(item, index) in advertBannerList" :key="index"></view>
</view> </view>
</view> </view>
<view class="time-box f26">{{$t('fn_313')+': '}}<text class="domation">{{nowDate}}</text></view> <!-- <view class="time-box f26">{{$t('fn_313')+': '}}<text class="domation">{{nowDate}}</text></view> -->
<annuity :userInfo="userInfo"></annuity> <annuity :userInfo="userInfo"></annuity>
<view class="nav-list"> <view class="nav-list">
<view class="nav-item" v-for="(item, index) in recommendSpecialAreaList" :key="index" v-if=" <view class="nav-item" v-for="(item, index) in recommendSpecialAreaList" :key="index" v-if="

View File

@ -222,20 +222,7 @@
<view class="p-40-0"> <view class="p-40-0">
<button class="normal-sub-btn" @click="payFunc">{{ $t('w_0248') }}</button> <button class="normal-sub-btn" @click="payFunc">{{ $t('w_0248') }}</button>
</view> </view>
<template v-if="showUp">
<view class="pop-bg"></view>
<view class="upgrade-pop">
<view class="d-e-c" @click="showUp = false"><u-icon name="close" size="32rpx" color="#fff"></u-icon></view>
<view class="fb white tc f48">升级成功</view>
<image style="width:100%;margin: 0 auto;" src="/static/cashier-up.png" mode="widthFix"></image>
<view class="progress-box"><view class="progress-box-item"></view></view>
<view class="d-c d-c-c white f28">
<view class="mb20">32100/49800</view>
<view class="mb20">您的最新等级为:VIP</view>
<view class="mb20">您的最新奖衔为:资深经理</view>
</view>
</view>
</template>
<Popup :show="isPopup" :width="665" :padding="0" @hidePopup="hidePopupFunc"> <Popup :show="isPopup" :width="665" :padding="0" @hidePopup="hidePopupFunc">
<view class="d-e-c ww100"> <view class="d-e-c ww100">
<view class="p20" @click="hidePopupFunc(true)"><text class="icon iconfont icon-guanbi" style="color: #999;font-size: 28rpx;"></text></view> <view class="p20" @click="hidePopupFunc(true)"><text class="icon iconfont icon-guanbi" style="color: #999;font-size: 28rpx;"></text></view>

View File

@ -342,7 +342,7 @@ export default {
methods: { methods: {
getOrderStatus() { getOrderStatus() {
let self = this; let self = this;
self._get("/system/pub/enums/order-status-api", {}, (res) => { self._get("system/pub/enums/order-status-api", {}, (res) => {
self.orderStatus = res.data; self.orderStatus = res.data;
}); });
}, },

View File

@ -24,7 +24,7 @@
<text class="domation mr10">*</text> <text class="domation mr10">*</text>
{{ $t("PER_DA_3") }} {{ $t("PER_DA_3") }}
</view> </view>
<view class="flex-1 d-s-c"> <view class="flex-1 d-s-c" style="width: 100%; justify-content: flex-end;">
<image <image
class="queryimg mr10" class="queryimg mr10"
mode="heightFix" mode="heightFix"
@ -34,7 +34,7 @@
: '' : ''
" "
></image> ></image>
<view class="flex-1">{{ <view >{{
pkCountry >= 0 && countryList[pkCountry] pkCountry >= 0 && countryList[pkCountry]
? countryList[pkCountry].shortName ? countryList[pkCountry].shortName
: "" : ""
@ -48,7 +48,7 @@
<text class="domation mr10">*</text> <text class="domation mr10">*</text>
{{ $t("PER_DA_4") }} {{ $t("PER_DA_4") }}
</view> </view>
<view class="flex-1 d-s-c"> <view class="flex-1 d-s-c" style="width: 100%; justify-content: flex-end;">
<image <image
class="queryimg mr10" class="queryimg mr10"
mode="heightFix" mode="heightFix"
@ -58,7 +58,7 @@
: '' : ''
" "
></image> ></image>
<view class="flex-1">{{ <view style="padding-right: 30rpx;">{{
pkSettleCountry >= 0 && countryList[pkSettleCountry] pkSettleCountry >= 0 && countryList[pkSettleCountry]
? countryList[pkSettleCountry].shortName ? countryList[pkSettleCountry].shortName
: "" : ""
@ -600,7 +600,8 @@ export default {
.queryimg { .queryimg {
height: 60rpx; height: 60rpx;
flex-shrink: 0; width: 60rpx;
// flex-shrink: 0;
} }
.form-top-nav { .form-top-nav {

View File

@ -305,7 +305,8 @@
} }
.queryimg { .queryimg {
height: 60rpx; height: 60rpx;
flex-shrink: 0; width: 60rpx;
// flex-shrink: 0;
} }
.form-title { .form-title {

View File

@ -674,13 +674,13 @@
methods: { methods: {
getMemberAnnuity() { getMemberAnnuity() {
let self = this; let self = this;
self._get("/member/api/member/get-member-annuity-time", {}, (res) => { self._get("member/api/member/get-member-annuity-time", {}, (res) => {
self.resaleIncomeBonus = res.data.resaleIncomeBonus; self.resaleIncomeBonus = res.data.resaleIncomeBonus;
}); });
}, },
getNextLevelPv() { getNextLevelPv() {
let self = this; let self = this;
self._get("/member/api/member/next-level-pv", {}, (res) => { self._get("member/api/member/next-level-pv", {}, (res) => {
self.nextText = res.data.gradeValue; self.nextText = res.data.gradeValue;
self.isMaxGrade = res.data.isMaxGrade; self.isMaxGrade = res.data.isMaxGrade;
}); });
@ -2029,7 +2029,8 @@
.queryimg { .queryimg {
height: 40rpx; height: 40rpx;
flex-shrink: 0; width: 40rpx;
// flex-shrink: 0;
margin: 0 10rpx; margin: 0 10rpx;
} }

View File

@ -317,7 +317,7 @@
}, },
getOrderStatus() { getOrderStatus() {
let self = this; let self = this;
self._get('/system/pub/enums/order-status-api', {}, res => { self._get('system/pub/enums/order-status-api', {}, res => {
self.orderStatus = res.data; self.orderStatus = res.data;
}) })
}, },