会员个人中心页面初步完成
This commit is contained in:
@@ -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');
|
||||
|
||||
|
||||
Reference in New Issue
Block a user