域名 AXUM.RS 将于 2025 年 10 月到期。我们无意再对其进行续费,如果你有意接续这个域名,请与我们取得联系。
  • AXUM.RS 现仅需人民币 3000 元(大写:叁仟元整。接受适度议价
  • 按照行业规则,AXUM.RS 到期后,大概率会进入长时间的赎回期,该期间内,如果你想拥有该域名,将要付出高额的费用
  • 我们已启用 AXUM.EU.ORG 域名,并将持续运营
  • 仅接受微信或支付宝交易
如果你对 AXUM.RS 有兴趣,请和我们进行联系:

用户积分变动记录

本章将实现用户查看本账号积分变动功能。本章包含后端和前端功能。

// src/db/pointer_log.rs

pub async fn list_all<'a>(c: impl PgExecutor<'a>, user_id: &'a str) -> Result<Vec<Model>> {
    let mut q = QueryBuilder::new(
        r#"SELECT id, user_id, dateline, pointer_amount, before_pointer, after_pointer, "note" FROM pointer_logs WHERE user_id="#,
    );
    q.push_bind(user_id)
        .push(" ORDER BY id DESC")
        .push(" LIMIT 50");
    q.build_query_as().fetch_all(c).await
}
  • 根据用户ID列出所有积分变动记录

前端

// src/pages/user/Pointer.tsx

import UserPageTitle from "@/components/UserPageTitle";
import { Component as PointerIcon } from "lucide-react";
import {
  Table,
  TableBody,
  TableCell,
  TableHead,
  TableHeader,
  TableRow,
} from "@/components/ui/table";
import { useEffect, useState } from "react";
import { $get, $ifApiErrorMsg, $isApiUnauthorizedError } from "@/lib/$fetch";
import use$status from "@/hooks/use$status";
import { useNavigate } from "react-router-dom";
import dayjs from "dayjs";

export default function UserPointerPage() {
  const [list, setList] = useState<PointerLog[]>([]);
  const { $setLoading, $setToast } = use$status();
  const navigate = useNavigate();

  const loadData = async () => {
    try {
      $setLoading(true);
      const res = await $get<PointerLog[]>("/user/pointer");
      if (res) {
        setList(res);
      }
    } catch (e) {
      if ($isApiUnauthorizedError(e)) {
        $setToast(e.message);
        return navigate("/login");
      }
      $setToast($ifApiErrorMsg(e));
    } finally {
      $setLoading(false);
    }
  };

  useEffect(() => {
    loadData();
  }, []);
  return (
    <>
      <div className="p-3 space-y-6">
        <section className="flex justify-between items-center gap-x-2 ">
          <UserPageTitle icon={<PointerIcon className="w-6" />}>
            积分记录
          </UserPageTitle>
        </section>

        <section className="my-6 bg-white rounded-md p-3">
          <Table>
            <TableHeader>
              <TableRow>
                <TableHead>#</TableHead>
                <TableHead>类型</TableHead>
                <TableHead>变动</TableHead>
                <TableHead>可用积分</TableHead>
                <TableHead>详情</TableHead>
                <TableHead>时间</TableHead>
              </TableRow>
            </TableHeader>
            <TableBody>
              {list.map((i) => (
                <TableRow key={i.id}>
                  <TableCell>
                    <div className="text-xs font-mono">{i.id}</div>
                  </TableCell>
                  <TableCell>
                    {i.pointer_amount > 0 ? "收入" : "消费"}
                  </TableCell>
                  <TableCell>
                    {i.pointer_amount > 0 ? (
                      <div className="text-green-600">+{i.pointer_amount}</div>
                    ) : (
                      <div className="text-red-600">{i.pointer_amount}</div>
                    )}
                  </TableCell>
                  <TableCell>{i.after_pointer}</TableCell>
                  <TableCell>{i.note}</TableCell>
                  <TableCell>
                    {dayjs(i.dateline).format("YYYY-MM-DD HH:mm:ss")}
                  </TableCell>
                </TableRow>
              ))}
            </TableBody>
          </Table>
        </section>
      </div>
    </>
  );
}

本章代码位于09.积分变动分支。

要查看完整内容,请先登录