Files
tuanwei-uniapp/src/pages/mine/qingma.vue
T
ticket-02 agent 81a093120c build(cli): 迁移到 uni-app 官方 Vite CLI 骨架(src/ 布局)
按地图口径把 HBuilderX 工程改成官方 #vite(JS 版)CLI 工程:

- 业务代码 git mv 进 src/(176 个 rename,逐文件字节比对零内容改动):
  App.vue / main.js / manifest.json / pages.json / uni.scss /
  pages/ / packageMine/ / components/ / utils/ / static/ /
  uni_modules/ / uni.promisify.adaptor.js
- 新增官方骨架:package.json(@dcloudio/* 同版本 pin
  3.0.0-5020620260917001,vite 精确 5.2.8,vue ^3.4.21;只留 h5 与
  mp-weixin 脚本)、vite.config.js、shims-uni.d.ts;补 sass devDependency
  以支持既有 lang="scss"
- index.html 沿用本仓文件,入口改为 /src/main.js
- manifest.json 删除 app-plus / quickapp / mp-alipay / mp-baidu /
  mp-toutiao 五个死平台段,只留 mp-weixin
- .gitignore 加 dist/
- pnpm-workspace.yaml 新增 allowBuilds 白名单:pnpm 12 起
  onlyBuiltDependencies 已被移除,且 strictDepBuilds 默认 true 会把
  「未复核构建脚本」判成非零退出。白名单只列传递依赖
  esbuild / @parcel/watcher / core-js / core-js-pure。
  未使用 shamefully-hoist 或 node-linker=hoisted。

验收:pnpm build:mp-weixin 退出码 0,产物 app.json 的
pages / subPackages / tabBar / window 与改造前基线逐项一致;
project.config.json 落产物且 appid = wxf7ee9cd5801bf7a6。
2026-10-15 15:17:32 +08:00

345 lines
7.4 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<template>
<view class="page">
<scroll-view scroll-y class="page-scroll">
<view class="hero-card">
<view class="hero-title">我的“青马”</view>
<view class="hero-desc">查看青马工程报名记录、培养信息与当前审核状态。</view>
<view class="hero-stats">
<view class="stat-item">
<view class="stat-value">{{ records.length }}</view>
<view class="stat-label">记录总数</view>
</view>
<view class="stat-item">
<view class="stat-value">{{ approvedCount }}</view>
<view class="stat-label">已通过</view>
</view>
<view class="stat-item">
<view class="stat-value">{{ pendingCount }}</view>
<view class="stat-label">待跟进</view>
</view>
</view>
</view>
<view v-if="loading" class="state-card">
<view class="state-title">正在加载青马数据...</view>
<view class="state-desc">请稍候,正在同步你的青马工程记录。</view>
</view>
<view v-else-if="errorText" class="state-card state-card--error">
<view class="state-title">加载失败</view>
<view class="state-desc">{{ errorText }}</view>
</view>
<view v-else-if="!records.length" class="state-card">
<view class="state-title">暂未查询到青马记录</view>
<view class="state-desc">当前账号还没有青马工程报名或培养数据,可前往申报页查看开放项目。</view>
<view class="state-action" @tap="goApplyList">查看申报列表</view>
</view>
<view v-else class="card-list">
<view v-for="item in records" :key="item.id || `${item.name}-${item.year}`" class="data-card">
<view class="card-top">
<view class="card-main">
<view class="card-title">{{ item.name || '未命名学员' }}</view>
<view class="card-subtitle">{{ item.year || '未设置年度' }} · 青马工程</view>
</view>
<view class="status-tag" :class="`status-tag--${getStatusMeta(item).tone}`">
{{ getStatusMeta(item).text }}
</view>
</view>
<view class="meta-list">
<view class="meta-item">
<view class="meta-label">学校院系</view>
<view class="meta-value">{{ item.schoolInfo || '-' }}</view>
</view>
<view class="meta-item">
<view class="meta-label">手机号码</view>
<view class="meta-value">{{ item.phone || '-' }}</view>
</view>
<view class="meta-item">
<view class="meta-label">团学职务</view>
<view class="meta-value">{{ item.leaguePosition || '-' }}</view>
</view>
<view class="meta-item">
<view class="meta-label">综合成绩</view>
<view class="meta-value">{{ item.academicPerformance || '-' }}</view>
</view>
</view>
<view class="card-actions">
<view class="card-action" @tap="copyValue(item.phone)">复制电话</view>
<view class="card-action" @tap="copyValue(item.schoolInfo)">复制院系</view>
</view>
</view>
</view>
</scroll-view>
</view>
</template>
<script>
import { getReviewStatusMeta, userPageQmgcForm } from './service'
export default {
data() {
return {
loading: false,
errorText: '',
records: []
}
},
computed: {
approvedCount() {
return this.records.filter((item) => this.getStatusMeta(item).text === '通过').length
},
pendingCount() {
return this.records.filter((item) => this.getStatusMeta(item).text !== '通过').length
}
},
onShow() {
this.loadData()
},
onPullDownRefresh() {
this.loadData(true)
},
methods: {
getStatusMeta(item) {
return getReviewStatusMeta(item && item.reviewList)
},
async loadData(fromPullDown = false) {
this.loading = true
this.errorText = ''
try {
const result = await userPageQmgcForm({
page: 1,
limit: 20
})
this.records = (result && result.list) || []
} catch (error) {
this.errorText = (error && error.message) || '青马数据加载失败'
} finally {
this.loading = false
if (fromPullDown) {
uni.stopPullDownRefresh()
}
}
},
copyValue(value) {
if (!value) {
uni.showToast({
title: '暂无可复制内容',
icon: 'none'
})
return
}
uni.setClipboardData({
data: String(value),
success: () => {
uni.showToast({
title: '已复制',
icon: 'none'
})
}
})
},
goApplyList() {
uni.navigateTo({
url: '/pages/gxmu/index'
})
}
}
}
</script>
<style lang="scss" scoped>
.page {
min-height: 100vh;
background:
radial-gradient(circle at top center, rgba(184, 146, 33, 0.1), transparent 30%),
linear-gradient(180deg, #f8f4eb 0%, #f4efe5 100%);
}
.page-scroll {
height: 100vh;
padding: 24rpx 24rpx 40rpx;
}
.hero-card,
.state-card,
.data-card {
border-radius: 30rpx;
background: rgba(255, 255, 255, 0.94);
border: 1rpx solid rgba(184, 146, 33, 0.08);
box-shadow: 0 10rpx 28rpx rgba(76, 49, 35, 0.08);
}
.hero-card {
padding: 32rpx 28rpx;
background: linear-gradient(145deg, #6f4f05 0%, #a37a11 56%, #d4b24a 100%);
color: #fffdf4;
}
.hero-title {
font-size: 40rpx;
font-weight: 700;
}
.hero-desc {
margin-top: 14rpx;
font-size: 24rpx;
line-height: 1.7;
color: rgba(255, 253, 244, 0.86);
}
.hero-stats {
display: grid;
grid-template-columns: repeat(3, minmax(0, 1fr));
gap: 16rpx;
margin-top: 24rpx;
}
.stat-item {
padding: 18rpx 16rpx;
border-radius: 22rpx;
background: rgba(255, 255, 255, 0.12);
text-align: center;
}
.stat-value {
font-size: 32rpx;
font-weight: 700;
}
.stat-label {
margin-top: 6rpx;
font-size: 22rpx;
color: rgba(255, 253, 244, 0.8);
}
.state-card {
margin-top: 24rpx;
padding: 28rpx 24rpx;
}
.state-card--error {
border-color: rgba(195, 49, 30, 0.16);
}
.state-title {
font-size: 30rpx;
font-weight: 700;
color: #20252c;
}
.state-desc {
margin-top: 12rpx;
font-size: 24rpx;
line-height: 1.75;
color: #786e69;
}
.state-action {
margin-top: 18rpx;
font-size: 24rpx;
color: #a37a11;
font-weight: 700;
}
.card-list {
display: flex;
flex-direction: column;
gap: 18rpx;
margin-top: 24rpx;
}
.data-card {
padding: 24rpx;
}
.card-top {
display: flex;
align-items: flex-start;
justify-content: space-between;
gap: 16rpx;
}
.card-main {
flex: 1;
min-width: 0;
}
.card-title {
font-size: 30rpx;
font-weight: 700;
color: #22272f;
}
.card-subtitle {
margin-top: 8rpx;
font-size: 22rpx;
color: #8b817c;
}
.status-tag {
padding: 10rpx 16rpx;
border-radius: 999rpx;
font-size: 20rpx;
font-weight: 700;
}
.status-tag--success {
background: #eef9f1;
color: #1f8f49;
}
.status-tag--danger {
background: #fff1f0;
color: #d4380d;
}
.status-tag--warning {
background: #fff8e6;
color: #ad7b00;
}
.status-tag--default {
background: #f5f5f5;
color: #8b817c;
}
.meta-list {
display: flex;
flex-direction: column;
gap: 14rpx;
margin-top: 18rpx;
}
.meta-item {
padding: 18rpx;
border-radius: 22rpx;
background: #faf7f0;
}
.meta-label {
font-size: 20rpx;
color: #8b817c;
}
.meta-value {
margin-top: 8rpx;
font-size: 24rpx;
line-height: 1.7;
color: #2d333b;
word-break: break-all;
}
.card-actions {
display: flex;
gap: 14rpx;
margin-top: 18rpx;
}
.card-action {
padding: 10rpx 18rpx;
border-radius: 999rpx;
background: rgba(163, 122, 17, 0.08);
color: #a37a11;
font-size: 22rpx;
}
</style>