u
This commit is contained in:
1 parent
5d37c32081
commit
19b160620f
1 file changed
+183
-106
+183
-106
@@ -1,130 +1,207 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="zh-CN">
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<title>biz_key 私聊演示</title>
|
||||
<style>
|
||||
body {
|
||||
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI",
|
||||
Helvetica, Arial, sans-serif;
|
||||
background: #f5f7fa;
|
||||
padding: 40px;
|
||||
}
|
||||
<meta charset="UTF-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>记账列表</title>
|
||||
<script src="https://unpkg.com/vue@3/dist/vue.global.js"></script>
|
||||
|
||||
h1 {
|
||||
margin-bottom: 24px;
|
||||
}
|
||||
<style>
|
||||
* {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.container {
|
||||
display: flex;
|
||||
gap: 24px;
|
||||
align-items: flex-start;
|
||||
}
|
||||
body {
|
||||
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto;
|
||||
background: #f5f6f8;
|
||||
color: #333;
|
||||
}
|
||||
|
||||
.card {
|
||||
background: #fff;
|
||||
border-radius: 8px;
|
||||
padding: 16px;
|
||||
width: 240px;
|
||||
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.08);
|
||||
}
|
||||
.app {
|
||||
max-width: 480px;
|
||||
margin: 0 auto;
|
||||
background: #f5f6f8;
|
||||
min-height: 100vh;
|
||||
}
|
||||
|
||||
.card h2 {
|
||||
font-size: 16px;
|
||||
margin-bottom: 12px;
|
||||
border-bottom: 1px solid #eee;
|
||||
padding-bottom: 8px;
|
||||
}
|
||||
/* 顶部统计 */
|
||||
.summary {
|
||||
background: #ffffff;
|
||||
padding: 20px 16px;
|
||||
border-bottom: 1px solid #eee;
|
||||
}
|
||||
|
||||
.user {
|
||||
padding: 10px;
|
||||
margin-bottom: 8px;
|
||||
background: #f0f3f7;
|
||||
border-radius: 6px;
|
||||
}
|
||||
.summary-title {
|
||||
font-size: 14px;
|
||||
color: #888;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
.arrow {
|
||||
font-size: 32px;
|
||||
margin: 0 8px;
|
||||
align-self: center;
|
||||
}
|
||||
.summary-row {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
.biz {
|
||||
background: #e8f3ff;
|
||||
border: 1px dashed #409eff;
|
||||
padding: 12px;
|
||||
border-radius: 6px;
|
||||
text-align: center;
|
||||
font-weight: bold;
|
||||
color: #409eff;
|
||||
}
|
||||
.summary-item {
|
||||
text-align: center;
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.db-row {
|
||||
background: #f6ffed;
|
||||
border: 1px solid #b7eb8f;
|
||||
padding: 10px;
|
||||
border-radius: 6px;
|
||||
margin-bottom: 8px;
|
||||
font-family: monospace;
|
||||
font-size: 13px;
|
||||
}
|
||||
.summary-item span {
|
||||
display: block;
|
||||
font-size: 12px;
|
||||
color: #999;
|
||||
}
|
||||
|
||||
.note {
|
||||
margin-top: 24px;
|
||||
color: #666;
|
||||
font-size: 14px;
|
||||
}
|
||||
</style>
|
||||
.summary-item strong {
|
||||
font-size: 18px;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
/* 日期分组 */
|
||||
.date-group {
|
||||
margin-top: 12px;
|
||||
}
|
||||
|
||||
.date-header {
|
||||
padding: 8px 16px;
|
||||
font-size: 13px;
|
||||
color: #666;
|
||||
}
|
||||
|
||||
/* 账单项 */
|
||||
.record {
|
||||
background: #fff;
|
||||
padding: 14px 16px;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
border-bottom: 1px solid #f0f0f0;
|
||||
}
|
||||
|
||||
.record-left {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.record-type {
|
||||
font-size: 15px;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.record-desc {
|
||||
font-size: 12px;
|
||||
color: #999;
|
||||
margin-top: 4px;
|
||||
}
|
||||
|
||||
.record-amount {
|
||||
font-size: 16px;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.income {
|
||||
color: #2bb673;
|
||||
}
|
||||
|
||||
.expense {
|
||||
color: #e74c3c;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<h1>biz_key 私聊唯一性演示</h1>
|
||||
<div id="app" class="app">
|
||||
|
||||
<div class="container">
|
||||
<!-- 用户 -->
|
||||
<div class="card">
|
||||
<h2>用户</h2>
|
||||
<div class="user">用户 A<br />user_id = 1</div>
|
||||
<div class="user">用户 B<br />user_id = 2</div>
|
||||
</div>
|
||||
|
||||
<div class="arrow">➡️</div>
|
||||
|
||||
<!-- biz_key -->
|
||||
<div class="card">
|
||||
<h2>biz_key 生成</h2>
|
||||
<div class="biz">
|
||||
min(1,2) _ max(1,2)<br />
|
||||
= <br />
|
||||
<strong>1_2</strong>
|
||||
<!-- 顶部统计 -->
|
||||
<div class="summary">
|
||||
<div class="summary-title">本月统计</div>
|
||||
<div class="summary-row">
|
||||
<div class="summary-item">
|
||||
<span>收入</span>
|
||||
<strong class="income">{{ totalIncome }}</strong>
|
||||
</div>
|
||||
<div class="note">
|
||||
不管 A→B 还是 B→A<br />
|
||||
biz_key 都是一样的
|
||||
<div class="summary-item">
|
||||
<span>支出</span>
|
||||
<strong class="expense">{{ totalExpense }}</strong>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="arrow">➡️</div>
|
||||
|
||||
<!-- 数据库 -->
|
||||
<div class="card">
|
||||
<h2>数据库会话表</h2>
|
||||
<div class="db-row">
|
||||
id: 1001<br />
|
||||
space_id: 100<br />
|
||||
type: 私聊<br />
|
||||
biz_key: 1_2
|
||||
</div>
|
||||
<div class="note">
|
||||
唯一索引:<br />
|
||||
(space_id, type, biz_key)
|
||||
<div class="summary-item">
|
||||
<span>结余</span>
|
||||
<strong>{{ balance }}</strong>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="note">
|
||||
👉 结论:<br />
|
||||
<strong>biz_key = “这是谁和谁的私聊”</strong><br />
|
||||
<strong>id = “数据库给它的编号”</strong>
|
||||
<!-- 列表 -->
|
||||
<div v-for="group in groupedRecords" :key="group.date" class="date-group">
|
||||
<div class="date-header">{{ group.date }}</div>
|
||||
|
||||
<div
|
||||
v-for="item in group.list"
|
||||
:key="item.id"
|
||||
class="record"
|
||||
>
|
||||
<div class="record-left">
|
||||
<div class="record-type">{{ item.category }}</div>
|
||||
<div class="record-desc">{{ item.remark }}</div>
|
||||
</div>
|
||||
<div
|
||||
class="record-amount"
|
||||
:class="item.type === 'income' ? 'income' : 'expense'"
|
||||
>
|
||||
{{ item.type === 'income' ? '+' : '-' }}{{ item.amount }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<script>
|
||||
const { createApp } = Vue
|
||||
|
||||
createApp({
|
||||
data() {
|
||||
return {
|
||||
records: [
|
||||
{ id: 1, date: '2026-02-11', category: '餐饮', remark: '午餐', amount: 35, type: 'expense' },
|
||||
{ id: 2, date: '2026-02-11', category: '工资', remark: '2月工资', amount: 8000, type: 'income' },
|
||||
{ id: 3, date: '2026-02-10', category: '交通', remark: '地铁', amount: 6, type: 'expense' },
|
||||
{ id: 4, date: '2026-02-10', category: '购物', remark: '日用品', amount: 120, type: 'expense' }
|
||||
]
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
totalIncome() {
|
||||
return this.records
|
||||
.filter(r => r.type === 'income')
|
||||
.reduce((sum, r) => sum + r.amount, 0)
|
||||
},
|
||||
totalExpense() {
|
||||
return this.records
|
||||
.filter(r => r.type === 'expense')
|
||||
.reduce((sum, r) => sum + r.amount, 0)
|
||||
},
|
||||
balance() {
|
||||
return this.totalIncome - this.totalExpense
|
||||
},
|
||||
groupedRecords() {
|
||||
const groups = {}
|
||||
this.records.forEach(item => {
|
||||
if (!groups[item.date]) {
|
||||
groups[item.date] = []
|
||||
}
|
||||
groups[item.date].push(item)
|
||||
})
|
||||
return Object.keys(groups).map(date => ({
|
||||
date,
|
||||
list: groups[date]
|
||||
}))
|
||||
}
|
||||
}
|
||||
}).mount('#app')
|
||||
</script>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
Reference in new issue
Block a user