u
This commit is contained in:
1 parent
1903861354
commit
1b1a54f7dd
35 files changed
+1185
-535
No files matched your search
+62
-202
@@ -1,207 +1,67 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="zh-CN">
|
||||
<head>
|
||||
<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>
|
||||
import { useCallback } from 'react';
|
||||
import { StyleSheet, Text, View } from 'react-native';
|
||||
import Sortable from 'react-native-sortables';
|
||||
|
||||
<style>
|
||||
* {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
box-sizing: border-box;
|
||||
const DATA = Array.from({ length: 4 }, (_, index) => `Item ${index + 1}`);
|
||||
|
||||
export default function CustomHandleExample() {
|
||||
const renderItem = useCallback(
|
||||
({ item }: { item: string }) => (
|
||||
<View style={styles.card}>
|
||||
<Text style={styles.text}>{item}</Text>
|
||||
{/* Wraps the handle component */}
|
||||
{/* highlight-next-line */}
|
||||
<Sortable.Handle>
|
||||
<View style={styles.handle}>
|
||||
<Text style={styles.handleText}>::</Text>
|
||||
</View>
|
||||
{/* highlight-next-line */}
|
||||
</Sortable.Handle>
|
||||
</View>
|
||||
),
|
||||
[]
|
||||
);
|
||||
|
||||
return (
|
||||
<View style={styles.container}>
|
||||
<Sortable.Grid
|
||||
activeItemScale={1.05}
|
||||
columns={1}
|
||||
data={DATA}
|
||||
overDrag='vertical'
|
||||
renderItem={renderItem}
|
||||
rowGap={10}
|
||||
// highlight-next-line
|
||||
customHandle // must be set to use a custom handle
|
||||
/>
|
||||
</View>
|
||||
);
|
||||
}
|
||||
|
||||
body {
|
||||
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto;
|
||||
background: #f5f6f8;
|
||||
color: #333;
|
||||
}
|
||||
|
||||
.app {
|
||||
max-width: 480px;
|
||||
margin: 0 auto;
|
||||
background: #f5f6f8;
|
||||
min-height: 100vh;
|
||||
}
|
||||
|
||||
/* 顶部统计 */
|
||||
.summary {
|
||||
background: #ffffff;
|
||||
padding: 20px 16px;
|
||||
border-bottom: 1px solid #eee;
|
||||
}
|
||||
|
||||
.summary-title {
|
||||
font-size: 14px;
|
||||
color: #888;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
.summary-row {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
.summary-item {
|
||||
text-align: center;
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.summary-item span {
|
||||
display: block;
|
||||
font-size: 12px;
|
||||
color: #999;
|
||||
}
|
||||
|
||||
.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>
|
||||
<div id="app" class="app">
|
||||
|
||||
<!-- 顶部统计 -->
|
||||
<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="summary-item">
|
||||
<span>支出</span>
|
||||
<strong class="expense">{{ totalExpense }}</strong>
|
||||
</div>
|
||||
<div class="summary-item">
|
||||
<span>结余</span>
|
||||
<strong>{{ balance }}</strong>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 列表 -->
|
||||
<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' }
|
||||
]
|
||||
}
|
||||
const styles = StyleSheet.create({
|
||||
card: {
|
||||
alignItems: 'center',
|
||||
backgroundColor: '#2e8555',
|
||||
borderRadius: 12,
|
||||
flexDirection: 'row',
|
||||
justifyContent: 'center',
|
||||
padding: 24
|
||||
},
|
||||
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]
|
||||
}))
|
||||
}
|
||||
container: {
|
||||
padding: 16
|
||||
},
|
||||
handle: {
|
||||
backgroundColor: 'rgba(0,0,0,0.2)',
|
||||
borderRadius: 5,
|
||||
padding: 10
|
||||
},
|
||||
handleText: {
|
||||
color: 'white',
|
||||
fontWeight: 'bold'
|
||||
},
|
||||
text: {
|
||||
color: 'white',
|
||||
flex: 1,
|
||||
fontWeight: 'bold'
|
||||
}
|
||||
}).mount('#app')
|
||||
</script>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
});
|
||||
Reference in new issue
Block a user