This commit is contained in:
2025-09-20 12:05:53 +08:00
parent bff3d0414d
commit 9b107d665a
73 changed files with 2903 additions and 140 deletions

View File

@@ -0,0 +1,102 @@
"use strict";
const common_vendor = require("../../common/vendor.js");
const common_http = require("../../common/http.js");
const _sfc_main = {
data() {
return {
id: null,
form: { name: "", type: "cash", bankName: "", bankAccount: "", openingBalance: "" },
showType: false,
types: [
{ key: "cash", name: "现金" },
{ key: "bank", name: "银行存款" },
{ key: "wechat", name: "微信" },
{ key: "alipay", name: "支付宝" },
{ key: "other", name: "其他" }
]
};
},
onLoad(q) {
this.id = q && q.id ? Number(q.id) : null;
if (this.id)
this.load();
},
methods: {
typeLabel(t) {
const m = { cash: "现金", bank: "银行存款", wechat: "微信", alipay: "支付宝", other: "其他" };
return m[t] || t;
},
async load() {
try {
const list = await common_http.get("/api/accounts");
const a = (Array.isArray(list) ? list : (list == null ? void 0 : list.list) || []).find((x) => x.id == this.id);
if (a) {
this.form = { name: a.name, type: a.type, bankName: a.bank_name || a.bankName || "", bankAccount: a.bank_account || a.bankAccount || "", openingBalance: "" };
}
} catch (e) {
}
},
async save() {
if (!this.form.name) {
common_vendor.index.showToast({ title: "请输入名称", icon: "none" });
return;
}
try {
const body = { ...this.form, openingBalance: Number(this.form.openingBalance || 0) };
if (this.id)
await common_http.put(`/api/accounts/${this.id}`, body);
else
await common_http.post("/api/accounts", { ...body, status: 1 });
common_vendor.index.showToast({ title: "已保存", icon: "success" });
setTimeout(() => common_vendor.index.navigateBack(), 300);
} catch (e) {
common_vendor.index.showToast({ title: "保存失败", icon: "none" });
}
}
}
};
if (!Array) {
const _component_uni_popup = common_vendor.resolveComponent("uni-popup");
_component_uni_popup();
}
function _sfc_render(_ctx, _cache, $props, $setup, $data, $options) {
return common_vendor.e({
a: $data.form.name,
b: common_vendor.o(($event) => $data.form.name = $event.detail.value),
c: common_vendor.t($options.typeLabel($data.form.type)),
d: common_vendor.o(($event) => $data.showType = true),
e: $data.form.type === "bank"
}, $data.form.type === "bank" ? {
f: $data.form.bankName,
g: common_vendor.o(($event) => $data.form.bankName = $event.detail.value)
} : {}, {
h: $data.form.type === "bank"
}, $data.form.type === "bank" ? {
i: $data.form.bankAccount,
j: common_vendor.o(($event) => $data.form.bankAccount = $event.detail.value)
} : {}, {
k: $data.form.openingBalance,
l: common_vendor.o(($event) => $data.form.openingBalance = $event.detail.value),
m: common_vendor.o((...args) => $options.save && $options.save(...args)),
n: common_vendor.f($data.types, (t, k0, i0) => {
return {
a: common_vendor.t(t.name),
b: t.key,
c: common_vendor.o(($event) => {
$data.form.type = t.key;
$data.showType = false;
}, t.key)
};
}),
o: common_vendor.o(($event) => $data.showType = false),
p: common_vendor.sr("popup", "4430e2e8-0"),
q: common_vendor.o(($event) => $data.showType = $event),
r: common_vendor.p({
type: "bottom",
modelValue: $data.showType
})
});
}
const MiniProgramPage = /* @__PURE__ */ common_vendor._export_sfc(_sfc_main, [["render", _sfc_render]]);
wx.createPage(MiniProgramPage);
//# sourceMappingURL=../../../.sourcemap/mp-weixin/pages/account/form.js.map

View File

@@ -0,0 +1,4 @@
{
"navigationBarTitleText": "新增/编辑账户",
"usingComponents": {}
}

View File

@@ -0,0 +1 @@
<view class="page"><view class="form"><view class="field"><text class="label">账户名称</text><input class="input" placeholder="必填" value="{{a}}" bindinput="{{b}}"/></view><view class="field" bindtap="{{d}}"><text class="label">账户类型</text><text class="value">{{c}}</text></view><view wx:if="{{e}}" class="field"><text class="label">银行名称</text><input class="input" placeholder="选填" value="{{f}}" bindinput="{{g}}"/></view><view wx:if="{{h}}" class="field"><text class="label">银行账号</text><input class="input" placeholder="选填" value="{{i}}" bindinput="{{j}}"/></view><view class="field"><text class="label">当前余额</text><input class="input" type="number" placeholder="0.00" value="{{k}}" bindinput="{{l}}"/></view></view><view class="actions"><button class="primary" bindtap="{{m}}">保存</button></view><uni-popup wx:if="{{r}}" class="r" u-s="{{['d']}}" u-r="popup" u-i="4430e2e8-0" bind:__l="__l" bindupdateModelValue="{{q}}" u-p="{{r}}"><view class="sheet"><view wx:for="{{n}}" wx:for-item="t" wx:key="b" class="sheet-item" bindtap="{{t.c}}">{{t.a}}</view><view class="sheet-cancel" bindtap="{{o}}">取消</view></view></uni-popup></view>

View File

@@ -0,0 +1,23 @@
.page { display:flex; flex-direction: column; height: 100vh;
}
.form { background:#fff;
}
.field { display:flex; align-items:center; justify-content: space-between; padding: 18rpx 20rpx; border-bottom:1rpx solid #f3f3f3;
}
.label { color:#666;
}
.input { flex:1; text-align: right; color:#333;
}
.value { color:#333;
}
.actions { margin-top: 20rpx; padding: 0 20rpx;
}
.primary { width: 100%; background: #3c9cff; color:#fff; border-radius: 8rpx; padding: 22rpx 0;
}
.sheet { background:#fff;
}
.sheet-item { padding: 26rpx; text-align:center; border-bottom:1rpx solid #f2f2f2;
}
.sheet-cancel { padding: 26rpx; text-align:center; color:#666;
}

View File

@@ -0,0 +1,83 @@
"use strict";
const common_vendor = require("../../common/vendor.js");
const common_http = require("../../common/http.js");
const _sfc_main = {
data() {
return { accountId: null, startDate: "", endDate: "", list: [], opening: 0, income: 0, expense: 0, ending: 0 };
},
onLoad(query) {
this.accountId = Number(query && query.id);
this.quickInit();
this.load();
},
methods: {
quickInit() {
const now = /* @__PURE__ */ new Date();
const y = now.getFullYear(), m = now.getMonth() + 1;
this.startDate = `${y}-${String(m).padStart(2, "0")}-01`;
const lastDay = new Date(y, m, 0).getDate();
this.endDate = `${y}-${String(m).padStart(2, "0")}-${String(lastDay).padStart(2, "0")}`;
},
async load(page = 1, size = 50) {
try {
const res = await common_http.get(`/api/accounts/${this.accountId}/ledger`, { startDate: this.startDate, endDate: this.endDate, page, size });
this.list = res && res.list || [];
this.opening = Number(res && res.opening || 0);
this.income = Number(res && res.income || 0);
this.expense = Number(res && res.expense || 0);
this.ending = Number(res && res.ending || 0);
} catch (e) {
common_vendor.index.showToast({ title: "加载失败", icon: "none" });
}
},
fmt(v) {
return (typeof v === "number" ? v : Number(v || 0)).toFixed(2);
},
formatDate(s) {
if (!s)
return "-";
try {
const d = new Date(s);
const pad = (n) => String(n).padStart(2, "0");
return `${d.getFullYear()}-${pad(d.getMonth() + 1)}-${pad(d.getDate())} ${pad(d.getHours())}:${pad(d.getMinutes())}`;
} catch (e) {
return s;
}
}
}
};
function _sfc_render(_ctx, _cache, $props, $setup, $data, $options) {
return {
a: common_vendor.t($data.startDate || "—"),
b: $data.startDate,
c: common_vendor.o((e) => {
$data.startDate = e.detail.value;
$options.load();
}),
d: common_vendor.t($data.endDate || "—"),
e: $data.endDate,
f: common_vendor.o((e) => {
$data.endDate = e.detail.value;
$options.load();
}),
g: common_vendor.t($options.fmt($data.income)),
h: common_vendor.t($options.fmt($data.expense)),
i: common_vendor.t($options.fmt($data.opening)),
j: common_vendor.t($options.fmt($data.ending)),
k: common_vendor.f($data.list, (it, k0, i0) => {
return {
a: common_vendor.t(it.src === "other" ? it.category || "其他" : it.remark || "收付款"),
b: common_vendor.t(it.direction === "in" ? "+" : "-"),
c: common_vendor.t($options.fmt(it.amount)),
d: it.direction === "in" ? 1 : "",
e: it.direction === "out" ? 1 : "",
f: common_vendor.t($options.formatDate(it.tx_time || it.txTime)),
g: common_vendor.t(it.remark || "-"),
h: it.id
};
})
};
}
const MiniProgramPage = /* @__PURE__ */ common_vendor._export_sfc(_sfc_main, [["render", _sfc_render]]);
wx.createPage(MiniProgramPage);
//# sourceMappingURL=../../../.sourcemap/mp-weixin/pages/account/ledger.js.map

View File

@@ -0,0 +1,4 @@
{
"navigationBarTitleText": "账户流水",
"usingComponents": {}
}

View File

@@ -0,0 +1 @@
<view class="page"><view class="filters"><picker mode="date" value="{{b}}" bindchange="{{c}}"><view class="field"><text class="label">开始</text><text class="value">{{a}}</text></view></picker><picker mode="date" value="{{e}}" bindchange="{{f}}"><view class="field"><text class="label">结束</text><text class="value">{{d}}</text></view></picker></view><view class="summary"><view class="sum-item"><text class="k">收入</text><text class="v">{{g}}</text></view><view class="sum-item"><text class="k">支出</text><text class="v">{{h}}</text></view><view class="sum-item"><text class="k">期初</text><text class="v">{{i}}</text></view><view class="sum-item"><text class="k">期末</text><text class="v">{{j}}</text></view></view><scroll-view scroll-y class="list"><view wx:for="{{k}}" wx:for-item="it" wx:key="h" class="item"><view class="row"><text class="title">{{it.a}}</text><text class="{{['amount', it.d && 'in', it.e && 'out']}}">{{it.b}}{{it.c}}</text></view><view class="meta">{{it.f}} · {{it.g}}</view></view></scroll-view></view>

View File

@@ -0,0 +1,35 @@
.page { display:flex; flex-direction: column; height: 100vh;
}
.filters { display:flex; gap: 16rpx; padding: 16rpx; background:#fff;
}
.field { display:flex; justify-content: space-between; align-items:center; padding: 16rpx; border:1rpx solid #eee; border-radius: 12rpx; min-width: 300rpx;
}
.label { color:#666;
}
.value { color:#333;
}
.summary { display:grid; grid-template-columns: repeat(4,1fr); gap: 12rpx; padding: 12rpx 16rpx; background:#fff; border-top:1rpx solid #f1f1f1; border-bottom:1rpx solid #f1f1f1;
}
.sum-item { padding: 12rpx; text-align:center;
}
.k { display:block; color:#888; font-size: 24rpx;
}
.v { display:block; margin-top:6rpx; font-weight:700; color:#333;
}
.list { flex:1;
}
.item { padding: 18rpx 16rpx; border-bottom:1rpx solid #f4f4f4; background:#fff;
}
.row { display:flex; align-items:center; justify-content: space-between; margin-bottom: 6rpx;
}
.title { color:#333;
}
.amount { font-weight:700;
}
.amount.in { color:#2a9d8f;
}
.amount.out { color:#d35b5b;
}
.meta { color:#999; font-size: 24rpx;
}

View File

@@ -4,9 +4,10 @@ const common_http = require("../../common/http.js");
const TYPE_MAP = { cash: "现金", bank: "银行", alipay: "支付宝", wechat: "微信", other: "其他" };
const _sfc_main = {
data() {
return { accounts: [] };
return { accounts: [], mode: "view" };
},
async onLoad() {
async onLoad(q) {
this.mode = q && q.mode || "view";
try {
const res = await common_http.get("/api/accounts");
this.accounts = Array.isArray(res) ? res : (res == null ? void 0 : res.list) || [];
@@ -16,12 +17,19 @@ const _sfc_main = {
},
methods: {
select(a) {
const opener = getCurrentPages()[getCurrentPages().length - 2];
if (opener && opener.$vm) {
opener.$vm.selectedAccountId = a.id;
opener.$vm.selectedAccountName = a.name;
if (this.mode === "pick") {
const opener = getCurrentPages()[getCurrentPages().length - 2];
if (opener && opener.$vm) {
opener.$vm.selectedAccountId = a.id;
opener.$vm.selectedAccountName = a.name;
}
common_vendor.index.navigateBack();
} else {
common_vendor.index.navigateTo({ url: `/pages/account/ledger?id=${a.id}` });
}
common_vendor.index.navigateBack();
},
create() {
common_vendor.index.navigateTo({ url: "/pages/account/form" });
},
typeLabel(t) {
return TYPE_MAP[t] || t;
@@ -39,7 +47,8 @@ function _sfc_render(_ctx, _cache, $props, $setup, $data, $options) {
d: a.id,
e: common_vendor.o(($event) => $options.select(a), a.id)
};
})
}),
b: common_vendor.o((...args) => $options.create && $options.create(...args))
};
}
const MiniProgramPage = /* @__PURE__ */ common_vendor._export_sfc(_sfc_main, [["render", _sfc_render]]);

View File

@@ -1 +1 @@
<view class="page"><scroll-view scroll-y class="list"><view wx:for="{{a}}" wx:for-item="a" wx:key="d" class="item" bindtap="{{a.e}}"><view class="name">{{a.a}}</view><view class="meta">{{a.b}} · 余额:{{a.c}}</view></view></scroll-view></view>
<view class="page"><scroll-view scroll-y class="list"><view wx:for="{{a}}" wx:for-item="a" wx:key="d" class="item" bindtap="{{a.e}}"><view class="name">{{a.a}}</view><view class="meta">{{a.b}} · 余额:{{a.c}}</view></view></scroll-view><view class="fab" bindtap="{{b}}"></view></view>

View File

@@ -9,3 +9,5 @@
}
.meta { color:#888; font-size: 24rpx;
}
.fab { position: fixed; right: 32rpx; bottom: 120rpx; width: 100rpx; height: 100rpx; border-radius: 50%; background:#3c9cff; color:#fff; display:flex; align-items:center; justify-content:center; font-size: 52rpx; box-shadow: 0 10rpx 20rpx rgba(0,0,0,0.18);
}