Merge branch 'Branch_1' of https://git.u8t.cn/tangxinyue/alipay-emulator into Branch_1

This commit is contained in:
tangxinyue 2026-06-18 13:42:54 +08:00
commit c625b3472f
1 changed files with 191 additions and 272 deletions

View File

@ -26,12 +26,10 @@
</NavBar>
<view v-if="!selectedImage" :style="{'height':$systemInfo.statusBarHeight*2+88+'rpx'}">
</view>
<view class="group_48164">
<view class="rectangle_23292">
<image class="group_48163" src="/static/image/other/bank/gsyh/mrzh.png" />
<view class="flexcontainer_1">
<view class="rectangle_23290">
<image class="f0763869907c4a2a56d1061936006358" src="/static/image/other/bank/gsyh/gsyh.png" />
@ -41,7 +39,8 @@
<view class="text_3">
{{maskCardNumber(data.form.cardNumber)}}
<view
style="color:#3E82BD;margin-left: 52rpx;text-align: center;font-size: 22rpx; width: 52rpx;height: 32rpx;background: #F3F6FB;border-radius: 2px 2px 2px 2px;" @click="data.isShow=true">查看</view>
style="color:#3E82BD;margin-left: 52rpx;text-align: center;font-size: 22rpx; width: 52rpx;height: 32rpx;background: #F3F6FB;border-radius: 2px 2px 2px 2px;"
@click="data.isShow=true">查看</view>
</view>
</view>
</view>
@ -57,37 +56,31 @@
</view>
<view v-if="!selectedImage" class="image-box" @touchstart="handleTouchStart" @touchend="handleTouchEnd">
<image class="group_48140_3x" :src="data.bannerImage || '/static/image/other/bank/gsyh/gnimg.png'" mode="aspectFill" />
<!-- <view class="image-tip">
<text>长按替换真实截图</text>
</view> -->
<image class="group_48140_3x" :src="data.bannerImage || '/static/image/other/bank/gsyh/gnimg.png'"
mode="aspectFill" />
</view>
<view v-else class="scroll-image-box flex-1">
<scroll-view class="image-box h100" style="width: 100%;height: 182px;" scroll-y :show-scrollbar="false"
@scroll="onImageScroll">
<image class="crop-image-target" style="width:100%;" :src="selectedImage" mode="widthFix"></image>
</scroll-view>
<view class="dashed-line-box">
<view class="dashed-line-text">我是分割线</view>
</view>
</view>
<canvas canvas-id="crop-canvas"
style="position: fixed; left: -9999px; width: 750rpx; height: 100vh; pointer-events: none;"></canvas>
<!-- 蒙层 -->
<view v-if="showMask" class="mask" @click="closeMask">
<image class="mask-icon" src="/static/image/common/mask-icon.png" mode="widthFix">
</image>
<image class="mask-icon" src="/static/image/common/mask-icon.png" mode="widthFix"></image>
</view>
<!-- 卡号信息弹窗 -->
<view class="dask" v-if="data.isShow">
<view class="info">
<view class="title">
完整卡号
</view>
<view class="dec">
{{addSpaceEveryFourChars(data.form.cardNumber)}}
</view>
<view class="title">完整卡号</view>
<view class="dec">{{addSpaceEveryFourChars(data.form.cardNumber)}}</view>
<view class="btnbox">
<view class="btn" @click="data.isShow=false">取消</view>
<view class="btn btns" @click="data.isShow=false">复制卡号</view>
@ -100,7 +93,6 @@
<text class="text_7">限额</text>
<image class="group_48165" src="/static/image/other/bank/gsyh/titleIcon.png" />
</view>
<view class="panel_limits" @click="openEditDialog">
<view class="flexcontainer_4">
<view class="flexcontainer_5">
@ -108,22 +100,16 @@
<text class="text_9">日累积{{data.form.dayLimit}}</text>
</view>
<text class="text_10">{{data.form.dayRemain}}</text>
<view class="line">
<view class="line"></view>
</view>
</view>
<view class="flexcontainer_6">
<view class="flexcontainer_7">
<text class="text_11">当月剩余额度()</text>
<text class="text_12">日累积{{data.form.monthLimit}}</text>
</view>
<text class="text_13">{{data.form.monthRemain}}</text>
<view class="line">
<view class="line"></view>
</view>
</view>
<view class="flexcontainer_8">
<view class="flexcontainer_9">
<text class="text_14">当年剩余额度()</text>
@ -144,14 +130,12 @@
</view>
</view>
</view>
<view class="group_13989" @click="openEditDialog">
<view class="rectangle_23294_1">
<text class="text_19">启用日期</text>
<text class="text_20">{{data.form.startDate}}</text>
</view>
</view>
<view class="group_13990" @click="openEditDialog">
<view class="rectangle_23294_2">
<view class="rightInfo">
@ -161,7 +145,6 @@
<text class="text_22">{{data.form.endDate}}</text>
</view>
</view>
<view class="group_13991" @click="openEditDialog">
<view class="rectangle_23294_3">
<text class="text_23">设置别名</text>
@ -171,28 +154,24 @@
</view>
</view>
</view>
<view class="group_13992">
<view class="rectangle_23294_4">
<text class="text_25">账户互转</text>
<image class="group_13987_2" src="/static/image/other/bank/gsyh/rightIcon.png" />
</view>
</view>
<view class="group_13993">
<view class="rectangle_23294_5">
<text class="text_26">当面收款</text>
<image class="group_13987_3" src="/static/image/other/bank/gsyh/rightIcon.png" />
</view>
</view>
<view class="group_13994">
<view class="rectangle_23294_6">
<text class="text_27">绑手机号</text>
<image class="group_13987_4" src="/static/image/other/bank/gsyh/rightIcon.png" />
</view>
</view>
</view>
<view class="group_13994_1">
@ -205,9 +184,7 @@
<image class="group_13987_6" src="/static/image/other/bank/gsyh/rightIcon.png" />
</view>
<image class="dee351fc65540488ca79ac78c10072f2" src="/static/image/other/bank/gsyh/bottomImg.png" />
<view class="footer">
</view>
<view class="footer"></view>
<!-- 编辑弹窗 -->
<view v-if="editDialog.show" class="editDialog">
@ -218,7 +195,12 @@
<view class="editDialog_body">
<view class="formItem">
<text>余额</text>
<input v-model="editDialog.data.balance" type="digit" placeholder="请输入余额" />
<input
:value="editDialog.data.balance"
@input="(e) => onNumberInputRaw('balance', e.detail.value)"
type="digit"
placeholder="请输入余额"
/>
</view>
<view class="formItem">
<text>卡类型</text>
@ -230,27 +212,57 @@
</view>
<view class="formItem">
<text>当日额度上限</text>
<input :value="editDialog.data.dayLimit" @input="(e) => onNumberInput('dayLimit', e.detail.value)" placeholder="如: 50,000.00" />
<input
:value="editDialog.data.dayLimit"
@input="(e) => onNumberInputRaw('dayLimit', e.detail.value)"
type="digit"
placeholder="如: 50000"
/>
</view>
<view class="formItem">
<text>当日剩余额度</text>
<input :value="editDialog.data.dayRemain" @input="(e) => onNumberInput('dayRemain', e.detail.value)" placeholder="如: 50,000.00" />
<input
:value="editDialog.data.dayRemain"
@input="(e) => onNumberInputRaw('dayRemain', e.detail.value)"
type="digit"
placeholder="如: 50000"
/>
</view>
<view class="formItem">
<text>当月额度上限</text>
<input :value="editDialog.data.monthLimit" @input="(e) => onNumberInput('monthLimit', e.detail.value)" placeholder="如: 500,000.00" />
<input
:value="editDialog.data.monthLimit"
@input="(e) => onNumberInputRaw('monthLimit', e.detail.value)"
type="digit"
placeholder="如: 500000"
/>
</view>
<view class="formItem">
<text>当月剩余额度</text>
<input :value="editDialog.data.monthRemain" @input="(e) => onNumberInput('monthRemain', e.detail.value)" placeholder="如: 500,000.00" />
<input
:value="editDialog.data.monthRemain"
@input="(e) => onNumberInputRaw('monthRemain', e.detail.value)"
type="digit"
placeholder="如: 500000"
/>
</view>
<view class="formItem">
<text>当年额度上限</text>
<input :value="editDialog.data.yearLimit" @input="(e) => onNumberInput('yearLimit', e.detail.value)" placeholder="如: 2,500,000.00" />
<input
:value="editDialog.data.yearLimit"
@input="(e) => onNumberInputRaw('yearLimit', e.detail.value)"
type="digit"
placeholder="如: 2500000"
/>
</view>
<view class="formItem">
<text>当年剩余额度</text>
<input :value="editDialog.data.yearRemain" @input="(e) => onNumberInput('yearRemain', e.detail.value)" placeholder="如: 2,500,000.00" />
<input
:value="editDialog.data.yearRemain"
@input="(e) => onNumberInputRaw('yearRemain', e.detail.value)"
type="digit"
placeholder="如: 2500000"
/>
</view>
<view class="formItem">
<text>基本账户</text>
@ -277,6 +289,7 @@
</view>
</view>
</template>
<script setup>
import { reactive, onMounted, ref, getCurrentInstance } from 'vue';
import NavBar from '@/components/nav-bar/nav-bar'
@ -284,6 +297,7 @@ import NavBar from '@/components/nav-bar/nav-bar'
const instance = getCurrentInstance();
const CACHE_KEY = 'gsyh_account_info';
const BANNER_IMAGE_KEY = 'gsyh_banner_image';
const FONT_KEY = 'gsyh_font_path'; // key
const data = reactive({
form: {
@ -317,17 +331,13 @@ const editDialog = reactive({
onMounted(() => {
loadCache();
// banner
const savedBanner = uni.getStorageSync(BANNER_IMAGE_KEY);
if (savedBanner) {
data.bannerImage = savedBanner;
}
const config = uni.getStorageSync('config')
console.log("---config---", config);
const font = config.config['client.uniapp.font']
console.log("字体地址信息", font.bank);
// Font loading logic
const config = uni.getStorageSync('config');
const font = config.config['client.uniapp.font'];
const fontUrl = font.bank;
const fontName = 'zsyhFt';
@ -345,13 +355,12 @@ onMounted(() => {
};
// #ifdef H5
// H5 URL
loadFont(fontUrl);
// #endif
// #ifndef H5
// H5 使
const savedFontPath = uni.getStorageSync(' ');
// FONT_KEY
const savedFontPath = uni.getStorageSync(FONT_KEY);
if (savedFontPath) {
loadFont(savedFontPath);
} else {
@ -362,14 +371,10 @@ onMounted(() => {
uni.saveFile({
tempFilePath: res.tempFilePath,
success: (saveRes) => {
const savedPath = saveRes.savedFilePath;
uni.setStorageSync('certificate2_font_path', savedPath);
console.log("字体保存路径", savedPath);
loadFont(savedPath);
uni.setStorageSync(FONT_KEY, saveRes.savedFilePath); // key
loadFont(saveRes.savedFilePath);
},
fail: (err) => {
console.error('保存文件失败', err);
// Fallback:
fail: () => {
loadFont(res.tempFilePath);
}
});
@ -382,9 +387,11 @@ onMounted(() => {
}
// #endif
});
function back(){
uni.navigateBack()
function back() {
uni.navigateBack();
}
function loadCache() {
const cache = uni.getStorageSync(CACHE_KEY);
if (cache) {
@ -396,13 +403,32 @@ function saveCache() {
uni.setStorageSync(CACHE_KEY, data.form);
}
//
const NUMBER_FIELDS = ['balance', 'dayLimit', 'dayRemain', 'monthLimit', 'monthRemain', 'yearLimit', 'yearRemain'];
//
function toRawNumber(val) {
if (!val && val !== 0) return '';
return String(val).replace(/[^\d.]/g, '');
}
function openEditDialog() {
editDialog.data = JSON.parse(JSON.stringify(data.form));
const raw = JSON.parse(JSON.stringify(data.form));
// 便
NUMBER_FIELDS.forEach(field => {
raw[field] = toRawNumber(raw[field]);
});
editDialog.data = raw;
editDialog.show = true;
}
function saveEdit() {
data.form = { ...data.form, ...editDialog.data };
const saved = { ...editDialog.data };
//
NUMBER_FIELDS.forEach(field => {
saved[field] = formatNumber(saved[field]);
});
data.form = { ...data.form, ...saved };
saveCache();
editDialog.show = false;
uni.showToast({
@ -422,36 +448,8 @@ function addSpaceEveryFourChars(str) {
return str.replace(/(.{4})/g, '$1 ').trim();
}
function copyAll() {
const text = `户 名: ${data.form.name}\n卡 号: ${addSpaceEveryFourChars(data.form.cardNumber)}\n开户行: ${data.form.bankName}`;
uni.setClipboardData({
data: text,
success: () => {
uni.showToast({
title: '复制成功',
icon: 'success'
});
data.isShow = false;
}
});
}
function copyCardNumber() {
uni.setClipboardData({
data: data.form.cardNumber,
success: () => {
uni.showToast({
title: '复制成功',
icon: 'success'
});
data.isShow = false;
}
});
}
//
const handleTouchStart = (e) => {
// iOSHOME
const systemInfo = uni.getSystemInfoSync();
if (systemInfo.platform === 'ios' && systemInfo.safeAreaInsets?.bottom) {
const clientY = e.touches[0].clientY;
@ -460,7 +458,6 @@ const handleTouchStart = (e) => {
return;
}
}
longPressTimer = setTimeout(() => {
uni.vibrateShort();
chooseImage();
@ -474,128 +471,86 @@ const handleTouchEnd = () => {
}
};
//
const chooseImage = () => {
uni.chooseImage({
count: 1,
sourceType: ['album'],
success: (res) => {
selectedImage.value = res.tempFilePaths[0]
data.showMask = true
selectedImage.value = res.tempFilePaths[0];
data.showMask = true;
}
});
};
//
const closeMask = () => {
data.showMask = false
data.showMask = false;
};
//
const onImageScroll = (e) => {
scrollTop.value = e.detail.scrollTop;
};
//
const confirmImage = () => {
uni.showLoading({
title: '处理中...'
})
const query = uni.createSelectorQuery().in(instance)
//
query.select('.image-box').boundingClientRect()
query.select('.crop-image-target').boundingClientRect()
uni.showLoading({ title: '处理中...' });
const query = uni.createSelectorQuery().in(instance);
query.select('.image-box').boundingClientRect();
query.select('.crop-image-target').boundingClientRect();
query.exec(res => {
if (!res[0] || !res[1]) {
uni.hideLoading()
return
uni.hideLoading();
return;
}
console.log('rects', res)
const container = res[0] //
const image = res[1] //
//
const container = res[0];
const image = res[1];
uni.getImageInfo({
src: selectedImage.value,
success: (imgInfo) => {
const scale = imgInfo.width / image.width // 图片 原始宽 / 渲染宽
const sTop = scrollTop.value * scale // Y
const sHeight = container.height * scale //
// widthFix
const sWidth = imgInfo.width
// (使)
const canvasW = container.width
const canvasH = container.height
const ctx = uni.createCanvasContext('crop-canvas', instance)
//
ctx.clearRect(0, 0, canvasW, canvasH)
//
ctx.drawImage(
imgInfo.path,
0, sTop, sWidth, sHeight, //
0, 0, canvasW, canvasH //
)
const scale = imgInfo.width / image.width;
const sTop = scrollTop.value * scale;
const sHeight = container.height * scale;
const sWidth = imgInfo.width;
const canvasW = container.width;
const canvasH = container.height;
const ctx = uni.createCanvasContext('crop-canvas', instance);
ctx.clearRect(0, 0, canvasW, canvasH);
ctx.drawImage(imgInfo.path, 0, sTop, sWidth, sHeight, 0, 0, canvasW, canvasH);
ctx.draw(false, () => {
uni.canvasToTempFilePath({
canvasId: 'crop-canvas',
width: canvasW,
height: canvasH,
destWidth: sWidth, // 使,
destHeight: sHeight, // 使,
destWidth: sWidth,
destHeight: sHeight,
success: (res) => {
console.log('crop success (temp)', res.tempFilePath)
//
uni.saveFile({
tempFilePath: res.tempFilePath,
success: (saveRes) => {
console.log('save success (saved)', saveRes.savedFilePath)
data.bannerImage = saveRes.savedFilePath
selectedImage.value = '' //
//
uni.setStorageSync(BANNER_IMAGE_KEY, data.bannerImage)
uni.hideLoading()
},
fail: (err) => {
console.error('saveFile fail', err)
uni.hideLoading()
uni.showToast({
title: '保存失败',
icon: 'none'
})
}
})
},
fail: (err) => {
console.error(err)
uni.hideLoading()
uni.showToast({
title: '裁剪失败',
icon: 'none'
})
}
}, instance)
})
data.bannerImage = saveRes.savedFilePath;
selectedImage.value = '';
uni.setStorageSync(BANNER_IMAGE_KEY, data.bannerImage);
uni.hideLoading();
},
fail: () => {
uni.hideLoading()
uni.showToast({
title: '图片加载失败',
icon: 'none'
})
uni.hideLoading();
uni.showToast({ title: '保存失败', icon: 'none' });
}
})
})
});
},
fail: () => {
uni.hideLoading();
uni.showToast({ title: '裁剪失败', icon: 'none' });
}
}, instance);
});
},
fail: () => {
uni.hideLoading();
uni.showToast({ title: '图片加载失败', icon: 'none' });
}
});
});
};
//
const closeImageEdit = () => {
selectedImage.value = '';
};
@ -603,34 +558,31 @@ const closeImageEdit = () => {
//
function formatNumber(num) {
if (!num && num !== 0) return '';
//
let cleanNum = String(num).replace(/[^\d.]/g, '');
//
const parts = cleanNum.split('.');
if (parts.length > 2) {
cleanNum = parts[0] + '.' + parts.slice(1).join('');
}
//
let number = parseFloat(cleanNum);
if (isNaN(number)) return '';
//
number = Math.round(number * 100) / 100;
//
return number.toLocaleString('en-US', {
minimumFractionDigits: 2,
maximumFractionDigits: 2
});
}
//
function onNumberInput(field, value) {
editDialog.data[field] = formatNumber(value);
//
function onNumberInputRaw(field, value) {
editDialog.data[field] = value;
}
</script>
<style lang="scss" >
page{
<style lang="scss">
page {
background: #F8F8F8;
}
* {
box-sizing: border-box;
}
@ -651,6 +603,8 @@ function onNumberInput(field, value) {
width: 750rpx;
position: fixed;
z-index: 999;
left: 0;
top: 0;
background-color: #ffffff;
}
@ -690,11 +644,6 @@ function onNumberInput(field, value) {
justify-content: center;
}
.rectangle_18503 {
width: 240rpx;
height: 88rpx;
}
.text_1 {
font-size: 36rpx;
color: #617280;
@ -705,7 +654,8 @@ function onNumberInput(field, value) {
width: 240rpx;
height: 88rpx;
display: flex;
flex-direction: row; justify-content: flex-end;
flex-direction: row;
justify-content: flex-end;
align-items: center;
}
@ -716,11 +666,6 @@ function onNumberInput(field, value) {
margin-left: 28rpx;
}
.div_1 {
width: 754rpx;
height: 2rpx;
}
/* ===== card ===== */
.group_48164 {
width: 692rpx;
@ -735,12 +680,11 @@ function onNumberInput(field, value) {
border-radius: 20rpx;
background-color: #ffffff;
box-shadow: 0 0 20rpx rgba(0, 0, 0, 0.1);
padding: 40rpx 40rpx 20rpx 40rpx ;
padding: 40rpx 40rpx 20rpx 40rpx;
display: flex;
flex-direction: column;
justify-content: space-between;
position: relative;
}
.group_48163 {
@ -776,13 +720,6 @@ function onNumberInput(field, value) {
flex-direction: row;
}
.group_48162 {
width: 52rpx;
height: 32rpx;
margin-left: 20rpx;
margin-top: 46rpx;
}
.rectangle_23290 {
width: 108rpx;
height: 78rpx;
@ -877,7 +814,8 @@ function onNumberInput(field, value) {
align-items: center;
margin: 0 26rpx 0 26rpx;
position: relative;
.line{
.line {
width: calc(100%);
position: absolute;
height: 1rpx;
@ -886,13 +824,13 @@ function onNumberInput(field, value) {
left: 0;
}
}
.flexcontainer_5,
.flexcontainer_7,
.flexcontainer_9 {
display: flex;
flex-direction: column;
justify-content: center;
}
.text_8,
@ -917,14 +855,6 @@ function onNumberInput(field, value) {
font-weight: bold;
}
/* 分割线 */
.div_2,
.div_3 {
width: 694rpx;
height: 2rpx;
margin-left: 28rpx;
}
/* ===== list ===== */
.panel_limits_1 {
width: 750rpx;
@ -946,20 +876,27 @@ function onNumberInput(field, value) {
align-items: center;
border-bottom: 1rpx solid #eee;
justify-content: space-between;
.rightInfo{
.rightInfo {
display: flex;
align-items: center;
}
}
.text_20,.text_22{
.text_20,
.text_22 {
margin-right: 28rpx;
}
.text_18,.text_24{
}
.text_18,
.text_24 {
margin-right: 28rpx;
}
.text_24{
}
.text_24 {
color: #AAAAAA;
}
}
.text_17,
.text_19,
.text_21,
@ -1013,16 +950,12 @@ function onNumberInput(field, value) {
height: 200rpx;
margin-top: 12rpx;
}
.footer{
.footer {
width: 100%;
background-color: #ffffff;
height: 60rpx;
}
.home {
position: absolute;
bottom: 0;
left: 0;
}
/* 图片编辑样式 */
.image-box {
@ -1032,20 +965,6 @@ function onNumberInput(field, value) {
overflow: hidden;
}
.image-tip {
position: absolute;
bottom: 20rpx;
left: 50%;
transform: translateX(-50%);
background-color: rgba(0, 0, 0, 0.5);
padding: 10rpx 20rpx;
border-radius: 20rpx;
text {
font-size: 24rpx;
color: #fff;
}
}
.scroll-image-box {
width: 100%;
min-height: 0;
@ -1120,8 +1039,6 @@ function onNumberInput(field, value) {
display: flex;
flex-direction: column;
.title {
font-weight: 400;
font-size: 16px;
@ -1159,7 +1076,6 @@ function onNumberInput(field, value) {
}
.btns {
/* border-left: 1rpx solid #F2F2F2; */
color: #DA1C01;
}
}
@ -1205,7 +1121,9 @@ function onNumberInput(field, value) {
.editDialog_body {
padding: 20rpx 30rpx;
overflow-y: auto;
-webkit-overflow-scrolling: touch;
max-height: 60vh;
flex: 1;
}
.formItem {
@ -1255,10 +1173,11 @@ function onNumberInput(field, value) {
color: #fff;
}
}
.text_6,
.text_10,
.text_13,
.text_16{
font-family:"zsyhFt";
.text_16 {
font-family: "zsyhFt";
}
</style>