会员个人中心页面初步完成

This commit is contained in:
时舟年
2026-06-04 14:18:53 +08:00
committed by liwentao
parent 1fa2fbd3f3
commit a0026b1da5
170 changed files with 18092 additions and 35 deletions
@@ -0,0 +1,293 @@
/**
* 微信小程序组件/页面 WXSS 不支持本地 background-image
* 将 /static/images/ 背景图改为 <image> 标签,并清理 CSS。
*/
const fs = require('fs');
const path = require('path');
const root = path.join(__dirname, '..');
const COMPONENT_MAP = {
MemberInfoStatusBar: 'member-info-status-bar.css',
MemberInfoHeader: 'member-info-header.css',
MemberInfoMemberCard: 'member-info-member-card.css',
MemberInfoQuickActions: 'member-info-quick-actions.css',
MemberInfoBookingList: 'member-info-booking-list.css',
MemberInfoCheckInList: 'member-info-check-in-list.css',
MemberInfoBodyReport: 'member-info-body-report.css',
MemberInfoCouponPoints: 'member-info-coupon-points.css',
MemberInfoReferral: 'member-info-referral.css',
MemberInfoSettings: 'member-info-settings.css',
MemberInfoLogout: 'member-info-logout.css'
};
const PAGE_MAP = {
booking: ['booking-pixso.css'],
memberCard: ['member-card-pixso.css'],
userInfo: ['user-info-pixso.css']
};
function extractBgImages(css) {
const map = new Map();
const ruleRe = /^\.([a-zA-Z0-9_-]+)\s*\{([^}]*)\}/gm;
let match;
while ((match = ruleRe.exec(css)) !== null) {
const className = match[1];
const body = match[2];
const urlMatch = body.match(/background-image:\s*url\(\/static\/images\/([^)]+)\)/);
if (urlMatch) {
map.set(className, `/static/images/${urlMatch[1]}`);
}
}
return map;
}
function ensureImageDisplay(css, className) {
const ruleRe = new RegExp(`(\\.${className.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')}\\s*\\{)([^}]*)(\\})`);
return css.replace(ruleRe, (full, head, body, tail) => {
if (/display:\s*block/.test(body)) return full;
return `${head}${body.trim()}\n display: block;\n${tail}`;
});
}
function getMode(className) {
if (/avatar|banner|photo|card-preview|AC\d/i.test(className)) return 'aspectFill';
return 'aspectFit';
}
function replaceViewWithImage(template, className, src) {
const mode = getMode(className);
const imageTag = `<image class="${className}" src="${src}" mode="${mode}" />`;
const escaped = className.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
const patterns = [
new RegExp(`<view\\s+class="${escaped}"\\s*></view>`, 'g'),
new RegExp(`<view\\s+class="${escaped}"\\s*/>`, 'g'),
new RegExp(`<view\\s+class="${escaped}"\\s*>\\s*</view>`, 'g'),
new RegExp(`<view\\s+\\n\\s*class="${escaped}"\\s*\\n\\s*></view>`, 'g'),
new RegExp(`<view\\s+\\n\\s*class="${escaped}"\\s*\\n\\s*/>`, 'g'),
new RegExp(`<view\\s+[^>]*class="${escaped}"[^>]*>\\s*</view>`, 'g')
];
let result = template;
for (const re of patterns) {
result = result.replace(re, imageTag);
}
return result;
}
function stripAllLocalBgFromCss(css) {
let next = css;
next = next.replace(/background-image:\s*url\(\/static\/images\/[^)]+\);/g, '');
next = next.replace(/\n\s*background-size:\s*100%\s*100%;/g, '');
next = next.replace(/\n\s*background-repeat:\s*no-repeat;/g, '');
return next;
}
function convertPair(vuePath, cssPath) {
if (!fs.existsSync(vuePath) || !fs.existsSync(cssPath)) return;
let css = fs.readFileSync(cssPath, 'utf8');
const hadLocalBg = /background-image:\s*url\(\/static\/images\//.test(css);
if (!hadLocalBg) return;
const bgMap = extractBgImages(css);
let template = fs.readFileSync(vuePath, 'utf8');
const templateMatch = template.match(/<template>([\s\S]*?)<\/template>/);
if (!templateMatch) {
css = stripAllLocalBgFromCss(css);
fs.writeFileSync(cssPath, css, 'utf8');
console.log('css-only (no template)', path.relative(root, cssPath));
return;
}
let inner = templateMatch[1];
let changed = false;
for (const [className, src] of bgMap.entries()) {
const before = inner;
inner = replaceViewWithImage(inner, className, src);
if (inner !== before) {
changed = true;
css = ensureImageDisplay(css, className);
}
}
css = stripAllLocalBgFromCss(css);
if (changed) {
template = template.replace(templateMatch[1], inner);
fs.writeFileSync(vuePath, template, 'utf8');
}
fs.writeFileSync(cssPath, css, 'utf8');
console.log(
changed ? 'converted' : 'css-only',
path.relative(root, vuePath),
`(${bgMap.size} rules stripped)`
);
}
for (const [name, cssFile] of Object.entries(COMPONENT_MAP)) {
convertPair(
path.join(root, 'components/memberInfo', `${name}.vue`),
path.join(root, 'common/style/memberInfo', cssFile)
);
}
for (const [page, cssFiles] of Object.entries(PAGE_MAP)) {
for (const cssFile of cssFiles) {
convertPair(
path.join(root, 'pages/memberInfo', `${page}.vue`),
path.join(root, 'common/style/memberInfo/pages', cssFile)
);
}
}
console.log('done');