zjk
2026-04-17 a5e4aa6126766867000f1e27270ea317621ff3ea
feat: 添加个人中心页面
11个文件已添加
2个文件已修改
329 ■■■■■ 已修改文件
src/app.config.ts 1 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/pages/robotaxi/home/hooks/use-navigation.ts 5 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/robotaxi/assets/mine-all.png 补丁 | 查看 | 原始文档 | blame | 历史
src/robotaxi/assets/mine-arrow.png 补丁 | 查看 | 原始文档 | blame | 历史
src/robotaxi/assets/mine-back.png 补丁 | 查看 | 原始文档 | blame | 历史
src/robotaxi/assets/mine-bg.png 补丁 | 查看 | 原始文档 | blame | 历史
src/robotaxi/assets/mine-cancelled.png 补丁 | 查看 | 原始文档 | blame | 历史
src/robotaxi/assets/mine-finished.png 补丁 | 查看 | 原始文档 | blame | 历史
src/robotaxi/assets/mine-line.png 补丁 | 查看 | 原始文档 | blame | 历史
src/robotaxi/assets/mine-pay.png 补丁 | 查看 | 原始文档 | blame | 历史
src/robotaxi/pages/personal-center/index.config.ts 5 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/robotaxi/pages/personal-center/index.less 163 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/robotaxi/pages/personal-center/index.tsx 155 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/app.config.ts
@@ -37,6 +37,7 @@
        'pages/agreement-page/index',
        'pages/operating-area/index',
        'pages/share-trip/index',
        'pages/personal-center/index',
      ],
    },
    {
src/pages/robotaxi/home/hooks/use-navigation.ts
@@ -54,13 +54,12 @@
  };
  /**
   * 拨打客服。
   * 打开个人中心。
   */
  const openService = async () => {
    const ok = await ensureNetwork();
    if (!ok) return;
    const phoneNumber = Taro.getStorageSync('customerServicePhone');
    Taro.makePhoneCall({ phoneNumber });
    Taro.navigateTo({ url: '/robotaxi/pages/personal-center/index' });
  };
  /**
src/robotaxi/assets/mine-all.png
src/robotaxi/assets/mine-arrow.png
src/robotaxi/assets/mine-back.png
src/robotaxi/assets/mine-bg.png
src/robotaxi/assets/mine-cancelled.png
src/robotaxi/assets/mine-finished.png
src/robotaxi/assets/mine-line.png
src/robotaxi/assets/mine-pay.png
src/robotaxi/pages/personal-center/index.config.ts
New file
@@ -0,0 +1,5 @@
export default {
  navigationBarTitleText: '个人中心',
  navigationStyle: 'custom',
  disableScroll: false,
}
src/robotaxi/pages/personal-center/index.less
New file
@@ -0,0 +1,163 @@
.personal-center-page {
  min-height: 100vh;
  box-sizing: border-box;
  background-image: url("../../assets/mine-bg.png");
  background-size: 100% 804px;
  background-repeat: no-repeat;
  background-color: #f5f6fa;
}
.personal-center-header {
  padding: 108px 48px 0;
  display: flex;
  align-items: center;
  justify-content: space-between;
  .header-left {
    width: 48px;
    height: 48px;
  }
  .header-back-icon {
    width: 48px;
    height: 48px;
  }
}
.personal-center-content {
  padding: 52px 22px 0 24px;
}
.user-name {
  font-size: 36px;
  line-height: 48px;
  font-weight: 500;
  color: rgba(0, 0, 0, 0.9);
  margin-bottom: 48px;
  padding-left: 8px;
}
.coupon-card {
  height: 112px;
  border-radius: 16px;
  background: #fff5e5;
  box-sizing: border-box;
  border: 2px solid #ffffff;
  margin-bottom: 24px;
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 0 24px 0 42px;
  .coupon-card-title {
    font-size: 28px;
    line-height: 44px;
    color: rgba(0, 0, 0, 0.9);
  }
  .coupon-card-right {
    display: flex;
    align-items: center;
  }
  .coupon-card-count {
    font-size: 28px;
    line-height: 44px;
    color: rgba(0, 0, 0, 0.4);
    margin-right: 8px;
  }
  .coupon-card-arrow {
    width: 32px;
    height: 32px;
  }
}
.section-card {
  background: #ffffff;
  border-radius: 24px;
  padding: 24px 0;
  margin-bottom: 24px;
  &:last-child {
    padding: 32px 0;
    padding-bottom: 8px;
  }
}
.section-title {
  font-size: 28px;
  font-weight: 600;
  line-height: 44px;
  /* 文字色/黑色/重要字 90% */
  color: rgba(0, 0, 0, 0.9);
  text-indent: 32px;
  margin-bottom: 20px;
}
.section-card:last-child {
  .section-title {
    margin-bottom: 8px;
  }
}
.trip-menu {
  display: flex;
  align-items: center;
  padding-left: 8px;
}
.trip-menu-item {
  width: 172px;
  height: 120px;
  display: flex;
  flex-direction: column;
  align-items: center;
  position: relative;
}
.all {
  width: 134px;
}
.mine-line {
  position: absolute;
  left: 0;
  top: 0;
  width: 6px;
  height: 120px;
}
.trip-menu-icon {
  width: 80px;
  height: 80px;
  box-sizing: border-box;
}
.trip-menu-label {
  font-size: 24px;
  line-height: 40px;
  color: rgba(0, 0, 0, 0.9);
}
.tool-menu-item {
  height: 110px;
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding-left: 32px;
  padding-right: 24px;
  transition: background-color 0.2s;
}
.tool-menu-item-hover {
  background-color: rgba(0, 0, 0, 0.05);
}
.tool-menu-label {
  font-size: 28px;
  line-height: 44px;
  color: rgba(0, 0, 0, 0.9);
}
.tool-menu-arrow {
  width: 32px;
  height: 32px;
}
src/robotaxi/pages/personal-center/index.tsx
New file
@@ -0,0 +1,155 @@
import Taro from "@tarojs/taro";
import { View, Text, Image } from "@tarojs/components";
import { useState } from "react";
import backIcon from "../../assets/mine-back.png";
import mineArrow from "../../assets/mine-arrow.png";
import mineLine from "../../assets/mine-line.png";
import waitPay from "../../assets/mine-pay.png";
import finished from "../../assets/mine-finished.png";
import cancelled from "../../assets/mine-cancelled.png";
import all from "../../assets/mine-all.png";
import FavoritePopup from "../site-search/components/favorite-popup";
import "./index.less";
type TripMenuItem = {
  key: string;
  label: string;
  count?: string;
  icon: string;
};
type ToolMenuItem = {
  key: string;
  label: string;
};
const tripMenuList: TripMenuItem[] = [
  { key: "pending", label: "待支付", icon: waitPay },
  { key: "finished", label: "已完成", icon: finished },
  { key: "cancelled", label: "已取消", icon: cancelled },
  { key: "all", label: "全部订单", icon: all }
];
const toolMenuList: ToolMenuItem[] = [
  { key: "service", label: "联系客服" },
  { key: "invoice", label: "开发票" },
  { key: "payment", label: "支付设置" },
  { key: "favorite", label: "收藏站点" }
];
export default function PersonalCenter() {
  const nickname = Taro.getStorageSync("nickname") || "小鹏艺术家小鹏艺";
  const [showFavoritePopup, setShowFavoritePopup] = useState(false);
  const handleBack = () => {
    Taro.navigateBack({
      fail: () => Taro.reLaunch({ url: "/pages/robotaxi/home/index" })
    });
  };
  const handleTripClick = (key: string) => {
    if (
      key === "all" ||
      key === "pending" ||
      key === "finished" ||
      key === "cancelled"
    ) {
      Taro.navigateTo({ url: "/robotaxi/pages/order/index" });
    }
  };
  const handleToolClick = (key: string) => {
    if (key === "service") {
      const phoneNumber = Taro.getStorageSync("customerServicePhone");
      if (phoneNumber) {
        Taro.makePhoneCall({ phoneNumber });
      } else {
        Taro.showToast({ title: "暂无客服电话", icon: "none" });
      }
      return;
    }
    if (key === "favorite") {
      setShowFavoritePopup(true);
      return;
    }
    Taro.showToast({ title: "功能建设中", icon: "none" });
  };
  return (
    <View className="personal-center-page">
      <View className="personal-center-container">
        <View className="personal-center-header">
          <View className="header-left" onClick={handleBack}>
            <Image className="header-back-icon" src={backIcon} />
          </View>
        </View>
        <View className="personal-center-content">
          <View className="user-name">{nickname}</View>
          <View
            className="coupon-card"
            onClick={() =>
              Taro.navigateTo({ url: "/robotaxi/pages/coupon/index" })
            }
          >
            <Text className="coupon-card-title">我的优惠券</Text>
            <View className="coupon-card-right">
              <Text className="coupon-card-count">5张</Text>
              <Image className="coupon-card-arrow" src={mineArrow} />
            </View>
          </View>
          <View className="section-card">
            <View className="section-title">我的行程</View>
            <View className="trip-menu">
              {tripMenuList.map(item => (
                <View
                  key={item.key}
                  className={item.key === "all" ? "trip-menu-item all" : "trip-menu-item"}
                  onClick={() => handleTripClick(item.key)}
                >
                  {item.key === "all" && (
                    <Image className="mine-line" src={mineLine} />
                  )}
                  <Image className="trip-menu-icon" src={item.icon} />
                  <Text className="trip-menu-label">{item.label}</Text>
                </View>
              ))}
            </View>
          </View>
          <View className="section-card">
            <View className="section-title">服务与工具</View>
            <View className="tool-menu">
              {toolMenuList.map(item => (
                <View
                  key={item.key}
                  className="tool-menu-item"
                  hoverClass="tool-menu-item-hover"
                  onClick={() => handleToolClick(item.key)}
                >
                  <Text className="tool-menu-label">{item.label}</Text>
                  <Image className="tool-menu-arrow" src={mineArrow} />
                </View>
              ))}
            </View>
          </View>
        </View>
      </View>
      <FavoritePopup
        show={showFavoritePopup}
        onClose={() => setShowFavoritePopup(false)}
        onSelect={(item) => {
          console.log('Selected favorite item:', item);
          // TODO: handle favorite item selection
        }}
      />
    </View>
  );
}