基线:全量源码首提(D1 版本控制落地,含第一轮优化 B1-B4/A1/A4/缩放修复)

This commit is contained in:
dqb-dev
2026-10-01 22:15:22 +08:00
commit 1e65792b09
499 changed files with 204579 additions and 0 deletions
+162
View File
@@ -0,0 +1,162 @@
<!DOCTYPE html>
<html lang="zh">
<head>
<meta charset="utf-8">
<title>会员管理</title>
<style>
body { font-family: "Microsoft YaHei UI", "Microsoft YaHei", sans-serif; font-size: 14px; margin: 20px; background: #f5f6f8; }
h2 { margin: 0 0 14px; }
table { border-collapse: collapse; width: 100%; background: #fff; }
th, td { border: 1px solid #d0d4da; padding: 6px 10px; text-align: left; }
th { background: #eef1f5; }
tr:hover td { background: #f4f8ff; }
.bar { margin-bottom: 12px; }
button { padding: 5px 14px; cursor: pointer; }
input { padding: 4px 8px; }
.op button { margin-right: 4px; padding: 2px 8px; font-size: 12px; }
#tip { color: #2a7; margin-left: 10px; }
dialog { border: 1px solid #99a; border-radius: 6px; padding: 18px; }
dialog::backdrop { background: rgba(0,0,0,.3); }
dialog div { margin-bottom: 8px; }
dialog label { display: inline-block; width: 80px; }
dialog input { width: 200px; }
.nav { margin-bottom: 16px; }
.nav a { margin-right: 14px; color: #247; text-decoration: none; font-weight: 700; }
.nav a.cur { color: #f60; }
</style>
</head>
<body>
<div class="nav"><a class="cur" href="/admin.html">会员管理</a><a href="/xiangmu-cloud.html">项目云管理</a></div>
<h2>会员管理</h2>
<div class="bar">
手机号: <input id="q手机号" style="width:130px">
<button onclick="查询()">查询</button>
<button onclick="新增()">新增会员</button>
<button onclick="加载()">刷新列表</button>
<button onclick="保存()">保存修改</button>
<span id="tip"></span>
</div>
<table id="tbl">
<thead>
<tr><th style="width:40px"></th><th>手机号</th><th>密码</th><th>会员类型</th><th>有效期</th><th>注册时间</th><th>备注</th></tr>
</thead>
<tbody></tbody>
</table>
<dialog id="dlg新增">
<h3>新增会员</h3>
<div><label>手机号:</label><input id="n手机号"></div>
<div><label>密码:</label><input id="n密码"></div>
<div><label>会员类型:</label>
<select id="n类型" onchange="n类型改()">
<option>试用会员</option><option>月会员</option><option>季会员</option><option>年会员</option><option>永久会员</option>
</select>
</div>
<div><label>有效期:</label><input id="n有效期" placeholder="2027-05-13"></div>
<div style="text-align:right;margin-top:10px">
<button onclick="dlg新增.close()">取消</button>
<button onclick="确定新增()">确定</button>
</div>
</dialog>
<script>
var 数据 = [];
function 提示(s, ok) {
var t = document.getElementById('tip');
t.textContent = s; t.style.color = ok ? '#2a7' : '#c33';
setTimeout(function(){ t.textContent=''; }, 3000);
}
// 会员类型 → 有效期天数(永久会员=永久);改类型时自动算有效期
var 类型天数 = { '试用会员': 30, '月会员': 1, '季会员': 3, '年会员': 12, '永久会员': 0 };
function 今天加月(n) {
var d = new Date(); d.setMonth(d.getMonth() + n);
return d.getFullYear() + '-' + ('0'+(d.getMonth()+1)).slice(-2) + '-' + ('0'+d.getDate()).slice(-2);
}
function 改类型(i, v) {
if (!数据[i]) return;
数据[i]['会员类型'] = v;
var n = 类型天数[v];
if (n === undefined) return; // 自定义类型不动有效期
数据[i]['有效期'] = n === 0 ? '永久' : 今天加月(n);
渲染(); // 重渲染让有效期输入框同步显示新值
}
function 加载() {
fetch('/api/list').then(r => r.json()).then(j => {
数据 = j['会员'] || [];
渲染();
});
}
function 渲染() {
var q = document.getElementById('q手机号').value.trim();
var tb = document.getElementById('tbl').getElementsByTagName('tbody')[0];
tb.innerHTML = '';
数据.forEach(function (m, i) {
if (q && (m['手机号']||'').indexOf(q) < 0) return;
var tr = tb.insertRow();
tr.insertCell().innerHTML = '<input type="checkbox" data-i="'+i+'" class="sel">';
tr.insertCell().innerHTML = '<input value="'+(m['手机号']||'')+'" onchange="改('+i+',\'手机号\',this.value)" style="width:120px">';
tr.insertCell().innerHTML = '<input value="'+(m['密码']||'')+'" onchange="改('+i+',\'密码\',this.value)" style="width:100px">';
tr.insertCell().innerHTML = '<select onchange="改类型('+i+',this.value)" style="width:90px">'
+ ['试用会员','月会员','季会员','年会员','永久会员'].map(function(t){ return '<option'+((m['会员类型']||'')===t?' selected':'')+'>'+t+'</option>'; }).join('')
+ '</select>';
tr.insertCell().innerHTML = '<input value="'+(m['有效期']||'')+'" onchange="改('+i+',\'有效期\',this.value)" style="width:100px">';
tr.insertCell().textContent = m['注册时间'] || '';
tr.insertCell().innerHTML = '<input value="'+(m['备注']||'')+'" onchange="改('+i+',\'备注\',this.value)" style="width:120px">';
var op = tr.insertCell(); op.className = 'op';
var del = document.createElement('button');
del.textContent = '删除';
del.onclick = function () {
if (!confirm('确定删除会员 ' + m['手机号'] + ' ?')) return;
数据.splice(i, 1); 渲染(); 保存();
};
op.appendChild(del);
});
}
function 改(i, k, v) { if (数据[i]) { 数据[i][k] = v; } }
// 新增弹窗:选类型 → 自动填有效期(手改过则以手改为准,切类型才覆盖)
function n类型改() {
var v = document.getElementById('n类型').value;
var n = 类型天数[v];
if (n === undefined) return;
document.getElementById('n有效期').value = n === 0 ? '永久' : 今天加月(n);
}
function 保存() {
fetch('/api/save', { method:'POST', headers:{'Content-Type':'application/json'},
body: JSON.stringify({ '会员': 数据 }) })
.then(r => r.json()).then(j => 提示(j.ok ? '已保存' : '保存失败:'+(j.msg||''), j.ok));
}
function 查询() { 渲染(); }
function 新增() { document.getElementById('dlg新增').showModal(); }
function 确定新增() {
var 手机号 = document.getElementById('n手机号').value.trim();
var 密码 = document.getElementById('n密码').value.trim();
if (!手机号 || !密码) { alert('手机号和密码不能为空'); return; }
fetch('/api/register', { method:'POST', headers:{'Content-Type':'application/json'},
body: JSON.stringify({ 手机号: 手机号, 密码: 密码 }) })
.then(r => r.json()).then(function (j) {
if (!j.ok) { alert(j.msg); return; }
// 注册默认"试用会员",把用户在弹窗选的类型/有效期补上
var 类型 = document.getElementById('n类型').value;
var 有效期 = document.getElementById('n有效期').value.trim();
加载后设置(手机号, 类型, 有效期);
document.getElementById('dlg新增').close();
});
}
function 加载后设置(手机号, 类型, 有效期) {
fetch('/api/list').then(r => r.json()).then(function (j) {
var list = j['会员'] || [];
list.forEach(function (m) {
if (m['手机号'] === 手机号) {
if (类型) m['会员类型'] = 类型;
if (有效期) m['有效期'] = 有效期;
}
});
fetch('/api/save', { method:'POST', headers:{'Content-Type':'application/json'},
body: JSON.stringify({ '会员': list }) }).then(function () { 加载(); });
});
}
加载();
</script>
</body>
</html>