feat: add contact management and various bug fixes
- Add contact API methods in athlete.js - Add contact list display in common-info.vue - Update add-contact.vue for contact creation - Create edit-contact page for contact editing - Fix event-register.vue with contact picker modal - Fix home.vue registration status display - Fix my-registration.vue cert modal display Co-authored-by: factory-droid[bot] <138933559+factory-droid[bot]@users.noreply.github.com>
This commit is contained in:
@@ -41,9 +41,6 @@ export default {
|
||||
|
||||
// ========== 集体/团队相关 API ==========
|
||||
|
||||
/**
|
||||
* 获取集体列表
|
||||
*/
|
||||
getTeamList(params = {}) {
|
||||
return request.get('/martial/team/list', {
|
||||
current: params.current || 1,
|
||||
@@ -52,24 +49,37 @@ export default {
|
||||
})
|
||||
},
|
||||
|
||||
/**
|
||||
* 获取集体详情
|
||||
*/
|
||||
getTeamDetail(id) {
|
||||
return request.get('/martial/team/detail', { id })
|
||||
},
|
||||
|
||||
/**
|
||||
* 保存集体
|
||||
*/
|
||||
saveTeam(data) {
|
||||
return request.post('/martial/team/submit', data)
|
||||
},
|
||||
|
||||
/**
|
||||
* 删除集体
|
||||
*/
|
||||
removeTeam(id) {
|
||||
return request.post('/martial/team/remove?id=' + id, {})
|
||||
},
|
||||
|
||||
// ========== 联系人相关 API ==========
|
||||
|
||||
getContactList(params = {}) {
|
||||
return request.get('/martial/contact/list', {
|
||||
current: params.current || 1,
|
||||
size: params.size || 100,
|
||||
...params
|
||||
})
|
||||
},
|
||||
|
||||
getContactDetail(id) {
|
||||
return request.get('/martial/contact/detail', { id })
|
||||
},
|
||||
|
||||
saveContact(data) {
|
||||
return request.post('/martial/contact/submit', data)
|
||||
},
|
||||
|
||||
removeContact(id) {
|
||||
return request.post('/martial/contact/remove?ids=' + id, {})
|
||||
}
|
||||
}
|
||||
|
||||
279
src/pages.json
279
src/pages.json
@@ -1,252 +1,35 @@
|
||||
{
|
||||
"pages": [
|
||||
{
|
||||
"path": "pages/login/login",
|
||||
"style": {
|
||||
"navigationBarTitleText": "登录",
|
||||
"navigationStyle": "custom"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "pages/register/register",
|
||||
"style": {
|
||||
"navigationBarTitleText": "注册",
|
||||
"navigationStyle": "custom"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "pages/home/home",
|
||||
"style": {
|
||||
"navigationBarTitleText": "武术赛事通",
|
||||
"navigationBarBackgroundColor": "#C93639",
|
||||
"navigationBarTextStyle": "white"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "pages/profile/profile",
|
||||
"style": {
|
||||
"navigationBarTitleText": "个人中心",
|
||||
"navigationBarBackgroundColor": "#C93639",
|
||||
"navigationBarTextStyle": "white"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "pages/change-password/change-password",
|
||||
"style": {
|
||||
"navigationBarTitleText": "修改密码",
|
||||
"navigationBarBackgroundColor": "#C93639",
|
||||
"navigationBarTextStyle": "white"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "pages/common-info/common-info",
|
||||
"style": {
|
||||
"navigationBarTitleText": "常用信息",
|
||||
"navigationBarBackgroundColor": "#C93639",
|
||||
"navigationBarTextStyle": "white"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "pages/add-player/add-player",
|
||||
"style": {
|
||||
"navigationBarTitleText": "新增选手",
|
||||
"navigationBarBackgroundColor": "#C93639",
|
||||
"navigationBarTextStyle": "white"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "pages/add-team/add-team",
|
||||
"style": {
|
||||
"navigationBarTitleText": "新增集体",
|
||||
"navigationBarBackgroundColor": "#C93639",
|
||||
"navigationBarTextStyle": "white"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "pages/edit-team/edit-team",
|
||||
"style": {
|
||||
"navigationBarTitleText": "编辑集体",
|
||||
"navigationBarBackgroundColor": "#C93639",
|
||||
"navigationBarTextStyle": "white"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "pages/edit-player/edit-player",
|
||||
"style": {
|
||||
"navigationBarTitleText": "编辑选手",
|
||||
"navigationBarBackgroundColor": "#C93639",
|
||||
"navigationBarTextStyle": "white"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "pages/add-contact/add-contact",
|
||||
"style": {
|
||||
"navigationBarTitleText": "新增联系人",
|
||||
"navigationBarBackgroundColor": "#C93639",
|
||||
"navigationBarTextStyle": "white"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "pages/my-registration/my-registration",
|
||||
"style": {
|
||||
"navigationBarTitleText": "我的报名",
|
||||
"navigationBarBackgroundColor": "#C93639",
|
||||
"navigationBarTextStyle": "white"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "pages/event-list/event-list",
|
||||
"style": {
|
||||
"navigationBarTitleText": "全部赛事列表",
|
||||
"navigationBarBackgroundColor": "#C93639",
|
||||
"navigationBarTextStyle": "white"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "pages/event-detail/event-detail",
|
||||
"style": {
|
||||
"navigationBarTitleText": "赛事详情",
|
||||
"navigationBarBackgroundColor": "#C93639",
|
||||
"navigationBarTextStyle": "white"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "pages/select-event/select-event",
|
||||
"style": {
|
||||
"navigationBarTitleText": "选择报名项目",
|
||||
"navigationBarBackgroundColor": "#C93639",
|
||||
"navigationBarTextStyle": "white"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "pages/event-register/event-register",
|
||||
"style": {
|
||||
"navigationBarTitleText": "赛事报名",
|
||||
"navigationBarBackgroundColor": "#C93639",
|
||||
"navigationBarTextStyle": "white"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "pages/register-type/register-type",
|
||||
"style": {
|
||||
"navigationBarTitleText": "选择报名",
|
||||
"navigationBarBackgroundColor": "#C93639",
|
||||
"navigationBarTextStyle": "white"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "pages/event-info/event-info",
|
||||
"style": {
|
||||
"navigationBarTitleText": "信息发布",
|
||||
"navigationBarBackgroundColor": "#C93639",
|
||||
"navigationBarTextStyle": "white"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "pages/event-info-detail/event-info-detail",
|
||||
"style": {
|
||||
"navigationBarTitleText": "信息详情",
|
||||
"navigationBarBackgroundColor": "#C93639",
|
||||
"navigationBarTextStyle": "white"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "pages/event-rules/event-rules",
|
||||
"style": {
|
||||
"navigationBarTitleText": "赛事规程",
|
||||
"navigationBarBackgroundColor": "#C93639",
|
||||
"navigationBarTextStyle": "white"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "pages/event-schedule/event-schedule",
|
||||
"style": {
|
||||
"navigationBarTitleText": "活动日程",
|
||||
"navigationBarBackgroundColor": "#C93639",
|
||||
"navigationBarTextStyle": "white"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "pages/event-players/event-players",
|
||||
"style": {
|
||||
"navigationBarTitleText": "参赛选手",
|
||||
"navigationBarBackgroundColor": "#C93639",
|
||||
"navigationBarTextStyle": "white"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "pages/event-live/event-live",
|
||||
"style": {
|
||||
"navigationBarTitleText": "比赛实况",
|
||||
"navigationBarBackgroundColor": "#C93639",
|
||||
"navigationBarTextStyle": "white"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "pages/event-lineup/event-lineup",
|
||||
"style": {
|
||||
"navigationBarTitleText": "出场顺序",
|
||||
"navigationBarBackgroundColor": "#C93639",
|
||||
"navigationBarTextStyle": "white"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "pages/event-score/event-score",
|
||||
"style": {
|
||||
"navigationBarTitleText": "成绩",
|
||||
"navigationBarBackgroundColor": "#C93639",
|
||||
"navigationBarTextStyle": "white"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "pages/event-medals/event-medals",
|
||||
"style": {
|
||||
"navigationBarTitleText": "奖牌榜",
|
||||
"navigationBarBackgroundColor": "#C93639",
|
||||
"navigationBarTextStyle": "white"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "pages/attachment-view/attachment-view",
|
||||
"style": {
|
||||
"navigationBarTitleText": "附件查看",
|
||||
"navigationBarBackgroundColor": "#C93639",
|
||||
"navigationBarTextStyle": "white"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "pages/event-photos/event-photos",
|
||||
"style": {
|
||||
"navigationBarTitleText": "图片直播",
|
||||
"navigationBarBackgroundColor": "#C93639",
|
||||
"navigationBarTextStyle": "white"
|
||||
}
|
||||
}
|
||||
{"path": "pages/login/login", "style": {"navigationBarTitleText": "登录", "navigationStyle": "custom"}},
|
||||
{"path": "pages/register/register", "style": {"navigationBarTitleText": "注册", "navigationStyle": "custom"}},
|
||||
{"path": "pages/home/home", "style": {"navigationBarTitleText": "武术赛事通", "navigationBarBackgroundColor": "#C93639", "navigationBarTextStyle": "white"}},
|
||||
{"path": "pages/profile/profile", "style": {"navigationBarTitleText": "个人中心", "navigationBarBackgroundColor": "#C93639", "navigationBarTextStyle": "white"}},
|
||||
{"path": "pages/change-password/change-password", "style": {"navigationBarTitleText": "修改密码", "navigationBarBackgroundColor": "#C93639", "navigationBarTextStyle": "white"}},
|
||||
{"path": "pages/common-info/common-info", "style": {"navigationBarTitleText": "常用信息", "navigationBarBackgroundColor": "#C93639", "navigationBarTextStyle": "white"}},
|
||||
{"path": "pages/add-player/add-player", "style": {"navigationBarTitleText": "新增选手", "navigationBarBackgroundColor": "#C93639", "navigationBarTextStyle": "white"}},
|
||||
{"path": "pages/add-team/add-team", "style": {"navigationBarTitleText": "新增集体", "navigationBarBackgroundColor": "#C93639", "navigationBarTextStyle": "white"}},
|
||||
{"path": "pages/edit-team/edit-team", "style": {"navigationBarTitleText": "编辑集体", "navigationBarBackgroundColor": "#C93639", "navigationBarTextStyle": "white"}},
|
||||
{"path": "pages/edit-player/edit-player", "style": {"navigationBarTitleText": "编辑选手", "navigationBarBackgroundColor": "#C93639", "navigationBarTextStyle": "white"}},
|
||||
{"path": "pages/add-contact/add-contact", "style": {"navigationBarTitleText": "新增联系人", "navigationBarBackgroundColor": "#C93639", "navigationBarTextStyle": "white"}},
|
||||
{"path": "pages/edit-contact/edit-contact", "style": {"navigationBarTitleText": "编辑联系人", "navigationBarBackgroundColor": "#C93639", "navigationBarTextStyle": "white"}},
|
||||
{"path": "pages/my-registration/my-registration", "style": {"navigationBarTitleText": "我的报名", "navigationBarBackgroundColor": "#C93639", "navigationBarTextStyle": "white"}},
|
||||
{"path": "pages/event-list/event-list", "style": {"navigationBarTitleText": "全部赛事列表", "navigationBarBackgroundColor": "#C93639", "navigationBarTextStyle": "white"}},
|
||||
{"path": "pages/event-detail/event-detail", "style": {"navigationBarTitleText": "赛事详情", "navigationBarBackgroundColor": "#C93639", "navigationBarTextStyle": "white"}},
|
||||
{"path": "pages/select-event/select-event", "style": {"navigationBarTitleText": "选择报名项目", "navigationBarBackgroundColor": "#C93639", "navigationBarTextStyle": "white"}},
|
||||
{"path": "pages/event-register/event-register", "style": {"navigationBarTitleText": "赛事报名", "navigationBarBackgroundColor": "#C93639", "navigationBarTextStyle": "white"}},
|
||||
{"path": "pages/register-type/register-type", "style": {"navigationBarTitleText": "选择报名", "navigationBarBackgroundColor": "#C93639", "navigationBarTextStyle": "white"}},
|
||||
{"path": "pages/event-info/event-info", "style": {"navigationBarTitleText": "信息发布", "navigationBarBackgroundColor": "#C93639", "navigationBarTextStyle": "white"}},
|
||||
{"path": "pages/event-info-detail/event-info-detail", "style": {"navigationBarTitleText": "信息详情", "navigationBarBackgroundColor": "#C93639", "navigationBarTextStyle": "white"}},
|
||||
{"path": "pages/event-rules/event-rules", "style": {"navigationBarTitleText": "赛事规程", "navigationBarBackgroundColor": "#C93639", "navigationBarTextStyle": "white"}},
|
||||
{"path": "pages/event-schedule/event-schedule", "style": {"navigationBarTitleText": "活动日程", "navigationBarBackgroundColor": "#C93639", "navigationBarTextStyle": "white"}},
|
||||
{"path": "pages/event-players/event-players", "style": {"navigationBarTitleText": "参赛选手", "navigationBarBackgroundColor": "#C93639", "navigationBarTextStyle": "white"}},
|
||||
{"path": "pages/event-live/event-live", "style": {"navigationBarTitleText": "比赛实况", "navigationBarBackgroundColor": "#C93639", "navigationBarTextStyle": "white"}},
|
||||
{"path": "pages/event-lineup/event-lineup", "style": {"navigationBarTitleText": "出场顺序", "navigationBarBackgroundColor": "#C93639", "navigationBarTextStyle": "white"}},
|
||||
{"path": "pages/event-score/event-score", "style": {"navigationBarTitleText": "成绩", "navigationBarBackgroundColor": "#C93639", "navigationBarTextStyle": "white"}},
|
||||
{"path": "pages/event-medals/event-medals", "style": {"navigationBarTitleText": "奖牌榜", "navigationBarBackgroundColor": "#C93639", "navigationBarTextStyle": "white"}},
|
||||
{"path": "pages/attachment-view/attachment-view", "style": {"navigationBarTitleText": "附件查看", "navigationBarBackgroundColor": "#C93639", "navigationBarTextStyle": "white"}},
|
||||
{"path": "pages/event-photos/event-photos", "style": {"navigationBarTitleText": "图片直播", "navigationBarBackgroundColor": "#C93639", "navigationBarTextStyle": "white"}}
|
||||
],
|
||||
"globalStyle": {
|
||||
"navigationBarTextStyle": "white",
|
||||
"navigationBarTitleText": "武术赛事",
|
||||
"navigationBarBackgroundColor": "#C93639",
|
||||
"backgroundColor": "#F8F8F8"
|
||||
},
|
||||
"tabBar": {
|
||||
"color": "#999999",
|
||||
"selectedColor": "#C93639",
|
||||
"backgroundColor": "#ffffff",
|
||||
"borderStyle": "black",
|
||||
"list": [
|
||||
{
|
||||
"pagePath": "pages/home/home",
|
||||
"text": "首页",
|
||||
"iconPath": "static/images/首页灰@3x.png",
|
||||
"selectedIconPath": "static/images/首页亮@3x.png"
|
||||
},
|
||||
{
|
||||
"pagePath": "pages/profile/profile",
|
||||
"text": "个人中心",
|
||||
"iconPath": "static/images/个人中心灰@3x.png",
|
||||
"selectedIconPath": "static/images/个人中心亮@3x.png"
|
||||
}
|
||||
]
|
||||
}
|
||||
"globalStyle": {"navigationBarTextStyle": "white", "navigationBarTitleText": "武术赛事", "navigationBarBackgroundColor": "#C93639", "backgroundColor": "#F8F8F8"},
|
||||
"tabBar": {"color": "#999999", "selectedColor": "#C93639", "backgroundColor": "#ffffff", "borderStyle": "black", "list": [{"pagePath": "pages/home/home", "text": "首页", "iconPath": "static/images/首页灰@3x.png", "selectedIconPath": "static/images/首页亮@3x.png"}, {"pagePath": "pages/profile/profile", "text": "个人中心", "iconPath": "static/images/个人中心灰@3x.png", "selectedIconPath": "static/images/个人中心亮@3x.png"}]}
|
||||
}
|
||||
|
||||
@@ -13,82 +13,46 @@
|
||||
<view class="form-item">
|
||||
<view class="form-label">姓名</view>
|
||||
<view class="form-value">
|
||||
<input
|
||||
class="form-input"
|
||||
v-model="formData.name"
|
||||
placeholder="请输入姓名"
|
||||
placeholder-class="placeholder"
|
||||
/>
|
||||
<input class="form-input" v-model="formData.name" placeholder="请输入姓名" placeholder-class="placeholder" />
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class="form-item">
|
||||
<view class="form-label">证件号码</view>
|
||||
<view class="form-value">
|
||||
<input
|
||||
class="form-input"
|
||||
v-model="formData.idCard"
|
||||
placeholder="请输入身份证号码"
|
||||
placeholder-class="placeholder"
|
||||
/>
|
||||
<input class="form-input" v-model="formData.idCard" placeholder="请输入身份证号码" placeholder-class="placeholder" />
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class="form-item">
|
||||
<view class="form-label">手机号码</view>
|
||||
<view class="form-value">
|
||||
<input
|
||||
class="form-input"
|
||||
v-model="formData.phone"
|
||||
placeholder="请输入手机号码"
|
||||
placeholder-class="placeholder"
|
||||
type="number"
|
||||
/>
|
||||
<input class="form-input" v-model="formData.phone" placeholder="请输入手机号码" placeholder-class="placeholder" type="number" />
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class="form-item">
|
||||
<view class="form-label">邮箱</view>
|
||||
<view class="form-value">
|
||||
<input
|
||||
class="form-input"
|
||||
v-model="formData.email"
|
||||
placeholder="请输入邮箱"
|
||||
placeholder-class="placeholder"
|
||||
/>
|
||||
<input class="form-input" v-model="formData.email" placeholder="请输入邮箱" placeholder-class="placeholder" />
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class="form-item">
|
||||
<view class="form-label">地址</view>
|
||||
<view class="form-value">
|
||||
<input
|
||||
class="form-input"
|
||||
v-model="formData.address"
|
||||
placeholder="请输入地址"
|
||||
placeholder-class="placeholder"
|
||||
/>
|
||||
<input class="form-input" v-model="formData.address" placeholder="请输入地址" placeholder-class="placeholder" />
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class="form-item switch-item">
|
||||
<view class="form-label">设置为默认联系人</view>
|
||||
<view class="form-value">
|
||||
<switch
|
||||
:checked="formData.isDefault"
|
||||
@change="handleSwitchChange"
|
||||
color="#C93639"
|
||||
/>
|
||||
<switch :checked="formData.isDefault" @change="handleSwitchChange" color="#C93639" />
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 提示信息 -->
|
||||
<view class="hint-message" v-if="showHint">
|
||||
<text class="hint-icon">ℹ</text>
|
||||
<text class="hint-text">{{ hintText }}</text>
|
||||
</view>
|
||||
|
||||
<!-- Toast提示 -->
|
||||
<view class="toast-message" v-if="showToast">
|
||||
<text class="toast-text">{{ toastMessage }}</text>
|
||||
@@ -96,13 +60,16 @@
|
||||
|
||||
<!-- 按钮 -->
|
||||
<view class="btn-wrapper">
|
||||
<view class="btn save-btn disabled" v-if="!isFormValid">保存</view>
|
||||
<view class="btn save-btn" v-else @click="handleSave">保存</view>
|
||||
<view class="btn save-btn" :class="{ disabled: !isFormValid || saving }" @click="handleSave">
|
||||
{{ saving ? '保存中...' : '保存' }}
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import athleteAPI from '@/api/athlete.js';
|
||||
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
@@ -115,27 +82,20 @@ export default {
|
||||
address: '',
|
||||
isDefault: false
|
||||
},
|
||||
showHint: false,
|
||||
hintText: '',
|
||||
showToast: false,
|
||||
toastMessage: '',
|
||||
showIdTypePicker: false
|
||||
saving: false
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
isFormValid() {
|
||||
return (
|
||||
this.formData.name &&
|
||||
this.formData.idCard &&
|
||||
this.formData.phone &&
|
||||
this.validateIdCard(this.formData.idCard) &&
|
||||
this.validatePhone(this.formData.phone)
|
||||
);
|
||||
return this.formData.name && this.formData.idCard && this.formData.phone &&
|
||||
this.validateIdCard(this.formData.idCard) && this.validatePhone(this.formData.phone);
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
validateIdCard(idCard) {
|
||||
return /^\d{18}$/.test(idCard);
|
||||
return /^\d{17}[\dXx]$/.test(idCard);
|
||||
},
|
||||
validatePhone(phone) {
|
||||
return /^1\d{10}$/.test(phone);
|
||||
@@ -143,38 +103,34 @@ export default {
|
||||
handleSwitchChange(e) {
|
||||
this.formData.isDefault = e.detail.value;
|
||||
},
|
||||
handleSave() {
|
||||
if (!this.isFormValid) {
|
||||
if (this.formData.phone && !this.validatePhone(this.formData.phone)) {
|
||||
this.toastMessage = '手机号码格式不正确';
|
||||
this.showToast = true;
|
||||
setTimeout(() => {
|
||||
this.showToast = false;
|
||||
}, 2000);
|
||||
} else if (this.formData.idCard && !this.validateIdCard(this.formData.idCard)) {
|
||||
this.toastMessage = '身份证号码格式不正确';
|
||||
this.showToast = true;
|
||||
setTimeout(() => {
|
||||
this.showToast = false;
|
||||
}, 2000);
|
||||
} else {
|
||||
this.hintText = '请完善信息';
|
||||
this.showHint = true;
|
||||
setTimeout(() => {
|
||||
this.showHint = false;
|
||||
}, 2000);
|
||||
}
|
||||
showToastMsg(msg) {
|
||||
this.toastMessage = msg;
|
||||
this.showToast = true;
|
||||
setTimeout(() => { this.showToast = false; }, 2000);
|
||||
},
|
||||
async handleSave() {
|
||||
if (!this.isFormValid || this.saving) return;
|
||||
|
||||
if (!this.validatePhone(this.formData.phone)) {
|
||||
this.showToastMsg('手机号码格式不正确');
|
||||
return;
|
||||
}
|
||||
if (!this.validateIdCard(this.formData.idCard)) {
|
||||
this.showToastMsg('身份证号码格式不正确');
|
||||
return;
|
||||
}
|
||||
|
||||
// 实际保存逻辑
|
||||
uni.showToast({
|
||||
title: '保存成功',
|
||||
icon: 'success'
|
||||
});
|
||||
setTimeout(() => {
|
||||
uni.navigateBack();
|
||||
}, 1500);
|
||||
this.saving = true;
|
||||
try {
|
||||
await athleteAPI.saveContact(this.formData);
|
||||
uni.showToast({ title: '保存成功', icon: 'success' });
|
||||
setTimeout(() => { uni.navigateBack(); }, 1500);
|
||||
} catch (err) {
|
||||
console.error('保存联系人失败:', err);
|
||||
this.showToastMsg('保存失败,请重试');
|
||||
} finally {
|
||||
this.saving = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
@@ -201,13 +157,8 @@ export default {
|
||||
border-bottom: 1rpx solid #f5f5f5;
|
||||
}
|
||||
|
||||
.form-item:last-child {
|
||||
border-bottom: none;
|
||||
}
|
||||
|
||||
.switch-item {
|
||||
padding: 30rpx;
|
||||
}
|
||||
.form-item:last-child { border-bottom: none; }
|
||||
.switch-item { padding: 30rpx; }
|
||||
|
||||
.form-label {
|
||||
width: 180rpx;
|
||||
@@ -228,38 +179,8 @@ export default {
|
||||
color: #333333;
|
||||
}
|
||||
|
||||
.placeholder {
|
||||
color: #cccccc;
|
||||
}
|
||||
|
||||
.arrow {
|
||||
font-size: 40rpx;
|
||||
color: #cccccc;
|
||||
margin-left: 10rpx;
|
||||
}
|
||||
|
||||
.hint-message {
|
||||
position: fixed;
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
transform: translate(-50%, -50%);
|
||||
background-color: rgba(0, 0, 0, 0.7);
|
||||
color: #fff;
|
||||
padding: 30rpx 50rpx;
|
||||
border-radius: 16rpx;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 15rpx;
|
||||
z-index: 9999;
|
||||
}
|
||||
|
||||
.hint-icon {
|
||||
font-size: 40rpx;
|
||||
}
|
||||
|
||||
.hint-text {
|
||||
font-size: 28rpx;
|
||||
}
|
||||
.placeholder { color: #cccccc; }
|
||||
.arrow { font-size: 40rpx; color: #cccccc; margin-left: 10rpx; }
|
||||
|
||||
.toast-message {
|
||||
position: fixed;
|
||||
@@ -273,26 +194,7 @@ export default {
|
||||
z-index: 9999;
|
||||
}
|
||||
|
||||
.toast-text {
|
||||
font-size: 28rpx;
|
||||
}
|
||||
|
||||
.info-text {
|
||||
margin: 20rpx 30rpx;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.info-hint {
|
||||
font-size: 24rpx;
|
||||
color: #C93639;
|
||||
}
|
||||
|
||||
.warning-text {
|
||||
margin: 20rpx 30rpx;
|
||||
text-align: center;
|
||||
font-size: 24rpx;
|
||||
color: #C93639;
|
||||
}
|
||||
.toast-text { font-size: 28rpx; }
|
||||
|
||||
.btn-wrapper {
|
||||
position: fixed;
|
||||
|
||||
@@ -59,8 +59,31 @@
|
||||
<text class="empty-text">暂无集体信息</text>
|
||||
</view>
|
||||
|
||||
<!-- 联系人Tab内容 (Tab 2) -->
|
||||
<view class="empty-state" v-if="currentTab === 2">
|
||||
<!-- 联系人列表 (Tab 2) -->
|
||||
<view class="player-list" v-if="currentTab === 2 && contactList.length > 0">
|
||||
<view class="player-item" v-for="(item, index) in contactList" :key="index">
|
||||
<view class="player-info">
|
||||
<view class="player-name">
|
||||
{{ item.name }}
|
||||
<text class="default-tag" v-if="item.isDefault">默认</text>
|
||||
</view>
|
||||
<view class="player-id">手机:{{ item.phone }}</view>
|
||||
</view>
|
||||
<view class="player-actions">
|
||||
<view class="action-btn edit-btn" @click.stop="handleEditContact(item)">
|
||||
<image class="action-icon" src="/static/images/编辑@3x.png" mode="aspectFit"></image>
|
||||
<text>编辑</text>
|
||||
</view>
|
||||
<view class="action-btn delete-btn" @click.stop="handleDelete(item, 'contact')">
|
||||
<image class="action-icon" src="/static/images/删除@3x.png" mode="aspectFit"></image>
|
||||
<text>删除</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 联系人空状态 -->
|
||||
<view class="empty-state" v-if="currentTab === 2 && contactList.length === 0">
|
||||
<text class="empty-text">暂无联系人信息</text>
|
||||
</view>
|
||||
|
||||
@@ -98,6 +121,7 @@ export default {
|
||||
currentTab: 0,
|
||||
playerList: [],
|
||||
teamList: [],
|
||||
contactList: [],
|
||||
showDeleteModal: false,
|
||||
showSuccessToast: false,
|
||||
currentItem: null,
|
||||
@@ -111,31 +135,31 @@ export default {
|
||||
return '新增联系人'
|
||||
},
|
||||
deleteModalTitle() {
|
||||
return this.deleteType === 'team' ? '删除集体' : '删除选手'
|
||||
if (this.deleteType === 'team') return '删除集体'
|
||||
if (this.deleteType === 'contact') return '删除联系人'
|
||||
return '删除选手'
|
||||
},
|
||||
deleteModalContent() {
|
||||
return this.deleteType === 'team' ? '确定要删除该集体吗?' : '确定要删除该选手吗?'
|
||||
if (this.deleteType === 'team') return '确定要删除该集体吗?'
|
||||
if (this.deleteType === 'contact') return '确定要删除该联系人吗?'
|
||||
return '确定要删除该选手吗?'
|
||||
}
|
||||
},
|
||||
onLoad() {
|
||||
this.loadPlayerList()
|
||||
this.loadTeamList()
|
||||
this.loadContactList()
|
||||
},
|
||||
onShow() {
|
||||
this.loadPlayerList()
|
||||
this.loadTeamList()
|
||||
this.loadContactList()
|
||||
},
|
||||
methods: {
|
||||
/**
|
||||
* Load player list
|
||||
*/
|
||||
async loadPlayerList() {
|
||||
try {
|
||||
const userInfo = getUserInfo()
|
||||
if (!userInfo || !userInfo.userId) {
|
||||
console.error('未获取到用户信息')
|
||||
return
|
||||
}
|
||||
if (!userInfo || !userInfo.userId) return
|
||||
|
||||
const res = await athleteAPI.getAthleteList({
|
||||
current: 1,
|
||||
@@ -143,13 +167,7 @@ export default {
|
||||
createUser: userInfo.userId
|
||||
})
|
||||
|
||||
let list = []
|
||||
if (res.records) {
|
||||
list = res.records
|
||||
} else if (Array.isArray(res)) {
|
||||
list = res
|
||||
}
|
||||
|
||||
let list = res.records || (Array.isArray(res) ? res : [])
|
||||
this.playerList = list.map(item => ({
|
||||
id: item.id,
|
||||
name: item.name || item.playerName,
|
||||
@@ -163,17 +181,11 @@ export default {
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Load team list
|
||||
*/
|
||||
async loadTeamList() {
|
||||
try {
|
||||
const userInfo = getUserInfo()
|
||||
if (!userInfo || !userInfo.userId) {
|
||||
return
|
||||
}
|
||||
if (!userInfo || !userInfo.userId) return
|
||||
|
||||
// Try to load team list from API
|
||||
if (athleteAPI.getTeamList) {
|
||||
const res = await athleteAPI.getTeamList({
|
||||
current: 1,
|
||||
@@ -181,13 +193,7 @@ export default {
|
||||
createUser: userInfo.userId
|
||||
})
|
||||
|
||||
let list = []
|
||||
if (res.records) {
|
||||
list = res.records
|
||||
} else if (Array.isArray(res)) {
|
||||
list = res
|
||||
}
|
||||
|
||||
let list = res.records || (Array.isArray(res) ? res : [])
|
||||
this.teamList = list.map(item => ({
|
||||
id: item.id,
|
||||
name: item.name || item.teamName,
|
||||
@@ -200,33 +206,55 @@ export default {
|
||||
}
|
||||
},
|
||||
|
||||
async loadContactList() {
|
||||
try {
|
||||
const userInfo = getUserInfo()
|
||||
if (!userInfo || !userInfo.userId) return
|
||||
|
||||
if (athleteAPI.getContactList) {
|
||||
const res = await athleteAPI.getContactList({
|
||||
current: 1,
|
||||
size: 100,
|
||||
createUser: userInfo.userId
|
||||
})
|
||||
|
||||
let list = res.records || (Array.isArray(res) ? res : [])
|
||||
this.contactList = list.map(item => ({
|
||||
id: item.id,
|
||||
name: item.name,
|
||||
phone: item.phone,
|
||||
idCard: item.idCard,
|
||||
email: item.email,
|
||||
address: item.address,
|
||||
isDefault: item.isDefault
|
||||
}))
|
||||
}
|
||||
} catch (err) {
|
||||
console.error('加载联系人列表失败:', err)
|
||||
this.contactList = []
|
||||
}
|
||||
},
|
||||
|
||||
handleTabChange(index) {
|
||||
this.currentTab = index;
|
||||
},
|
||||
handleAdd() {
|
||||
if (this.currentTab === 0) {
|
||||
uni.navigateTo({
|
||||
url: '/pages/add-player/add-player'
|
||||
});
|
||||
uni.navigateTo({ url: '/pages/add-player/add-player' });
|
||||
} else if (this.currentTab === 1) {
|
||||
uni.navigateTo({
|
||||
url: '/pages/add-team/add-team'
|
||||
});
|
||||
uni.navigateTo({ url: '/pages/add-team/add-team' });
|
||||
} else if (this.currentTab === 2) {
|
||||
uni.navigateTo({
|
||||
url: '/pages/add-contact/add-contact'
|
||||
});
|
||||
uni.navigateTo({ url: '/pages/add-contact/add-contact' });
|
||||
}
|
||||
},
|
||||
handleEdit(item) {
|
||||
uni.navigateTo({
|
||||
url: '/pages/edit-player/edit-player?id=' + item.id
|
||||
});
|
||||
uni.navigateTo({ url: '/pages/edit-player/edit-player?id=' + item.id });
|
||||
},
|
||||
handleEditTeam(item) {
|
||||
uni.navigateTo({
|
||||
url: '/pages/edit-team/edit-team?id=' + item.id
|
||||
});
|
||||
uni.navigateTo({ url: '/pages/edit-team/edit-team?id=' + item.id });
|
||||
},
|
||||
handleEditContact(item) {
|
||||
uni.navigateTo({ url: '/pages/edit-contact/edit-contact?id=' + item.id });
|
||||
},
|
||||
handleDelete(item, type) {
|
||||
this.currentItem = item;
|
||||
@@ -242,27 +270,24 @@ export default {
|
||||
await athleteAPI.removeTeam(this.currentItem.id)
|
||||
}
|
||||
const index = this.teamList.findIndex(item => item.id === this.currentItem.id);
|
||||
if (index > -1) {
|
||||
this.teamList.splice(index, 1);
|
||||
if (index > -1) this.teamList.splice(index, 1);
|
||||
} else if (this.deleteType === 'contact') {
|
||||
if (athleteAPI.removeContact) {
|
||||
await athleteAPI.removeContact(this.currentItem.id)
|
||||
}
|
||||
const index = this.contactList.findIndex(item => item.id === this.currentItem.id);
|
||||
if (index > -1) this.contactList.splice(index, 1);
|
||||
} else {
|
||||
await athleteAPI.removeAthlete(this.currentItem.id)
|
||||
const index = this.playerList.findIndex(item => item.id === this.currentItem.id);
|
||||
if (index > -1) {
|
||||
this.playerList.splice(index, 1);
|
||||
}
|
||||
if (index > -1) this.playerList.splice(index, 1);
|
||||
}
|
||||
|
||||
this.showSuccessToast = true;
|
||||
setTimeout(() => {
|
||||
this.showSuccessToast = false;
|
||||
}, 2000);
|
||||
setTimeout(() => { this.showSuccessToast = false; }, 2000);
|
||||
} catch (err) {
|
||||
console.error('删除失败:', err)
|
||||
uni.showToast({
|
||||
title: '删除失败',
|
||||
icon: 'none'
|
||||
})
|
||||
uni.showToast({ title: '删除失败', icon: 'none' })
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -315,6 +340,18 @@ export default {
|
||||
font-weight: bold;
|
||||
color: #333333;
|
||||
margin-bottom: 10rpx;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 10rpx;
|
||||
}
|
||||
|
||||
.default-tag {
|
||||
font-size: 22rpx;
|
||||
color: #fff;
|
||||
background-color: #C93639;
|
||||
padding: 4rpx 12rpx;
|
||||
border-radius: 6rpx;
|
||||
font-weight: normal;
|
||||
}
|
||||
|
||||
.player-id {
|
||||
@@ -348,10 +385,6 @@ export default {
|
||||
border-color: #C93639;
|
||||
}
|
||||
|
||||
.icon {
|
||||
font-size: 28rpx;
|
||||
}
|
||||
|
||||
.action-icon {
|
||||
width: 28rpx;
|
||||
height: 28rpx;
|
||||
|
||||
249
src/pages/edit-contact/edit-contact.vue
Normal file
249
src/pages/edit-contact/edit-contact.vue
Normal file
@@ -0,0 +1,249 @@
|
||||
<template>
|
||||
<view class="add-contact-page">
|
||||
<view class="form-container">
|
||||
<view class="form-item" @click="showIdTypePicker = true">
|
||||
<view class="form-label">证件类型</view>
|
||||
<view class="form-value">
|
||||
<text>{{ formData.idType }}</text>
|
||||
<text class="arrow">›</text>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class="form-item">
|
||||
<view class="form-label">姓名</view>
|
||||
<view class="form-value">
|
||||
<input class="form-input" v-model="formData.name" placeholder="请输入姓名" placeholder-class="placeholder" />
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class="form-item">
|
||||
<view class="form-label">证件号码</view>
|
||||
<view class="form-value">
|
||||
<input class="form-input" v-model="formData.idCard" placeholder="请输入身份证号码" placeholder-class="placeholder" />
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class="form-item">
|
||||
<view class="form-label">手机号码</view>
|
||||
<view class="form-value">
|
||||
<input class="form-input" v-model="formData.phone" placeholder="请输入手机号码" placeholder-class="placeholder" type="number" />
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class="form-item">
|
||||
<view class="form-label">邮箱</view>
|
||||
<view class="form-value">
|
||||
<input class="form-input" v-model="formData.email" placeholder="请输入邮箱" placeholder-class="placeholder" />
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class="form-item">
|
||||
<view class="form-label">地址</view>
|
||||
<view class="form-value">
|
||||
<input class="form-input" v-model="formData.address" placeholder="请输入地址" placeholder-class="placeholder" />
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class="form-item switch-item">
|
||||
<view class="form-label">设置为默认联系人</view>
|
||||
<view class="form-value">
|
||||
<switch :checked="formData.isDefault" @change="handleSwitchChange" color="#C93639" />
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class="toast-message" v-if="showToast">
|
||||
<text class="toast-text">{{ toastMessage }}</text>
|
||||
</view>
|
||||
|
||||
<view class="btn-wrapper">
|
||||
<view class="btn save-btn" :class="{ disabled: !isFormValid || saving }" @click="handleSave">
|
||||
{{ saving ? '保存中...' : '保存' }}
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import athleteAPI from '@/api/athlete.js';
|
||||
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
contactId: null,
|
||||
formData: {
|
||||
idType: '身份证',
|
||||
name: '',
|
||||
idCard: '',
|
||||
phone: '',
|
||||
email: '',
|
||||
address: '',
|
||||
isDefault: false
|
||||
},
|
||||
showToast: false,
|
||||
toastMessage: '',
|
||||
saving: false
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
isFormValid() {
|
||||
return this.formData.name && this.formData.idCard && this.formData.phone &&
|
||||
this.validateIdCard(this.formData.idCard) && this.validatePhone(this.formData.phone);
|
||||
}
|
||||
},
|
||||
onLoad(options) {
|
||||
if (options.id) {
|
||||
this.contactId = options.id;
|
||||
this.loadContactDetail();
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
validateIdCard(idCard) {
|
||||
return /^\d{17}[\dXx]$/.test(idCard);
|
||||
},
|
||||
validatePhone(phone) {
|
||||
return /^1\d{10}$/.test(phone);
|
||||
},
|
||||
handleSwitchChange(e) {
|
||||
this.formData.isDefault = e.detail.value;
|
||||
},
|
||||
showToastMsg(msg) {
|
||||
this.toastMessage = msg;
|
||||
this.showToast = true;
|
||||
setTimeout(() => { this.showToast = false; }, 2000);
|
||||
},
|
||||
async loadContactDetail() {
|
||||
try {
|
||||
const res = await athleteAPI.getContactDetail(this.contactId);
|
||||
if (res) {
|
||||
this.formData = {
|
||||
idType: res.idType || '身份证',
|
||||
name: res.name || '',
|
||||
idCard: res.idCard || '',
|
||||
phone: res.phone || '',
|
||||
email: res.email || '',
|
||||
address: res.address || '',
|
||||
isDefault: res.isDefault || false
|
||||
};
|
||||
}
|
||||
} catch (err) {
|
||||
console.error('加载联系人详情失败:', err);
|
||||
this.showToastMsg('加载失败');
|
||||
}
|
||||
},
|
||||
async handleSave() {
|
||||
if (!this.isFormValid || this.saving) return;
|
||||
|
||||
if (!this.validatePhone(this.formData.phone)) {
|
||||
this.showToastMsg('手机号码格式不正确');
|
||||
return;
|
||||
}
|
||||
if (!this.validateIdCard(this.formData.idCard)) {
|
||||
this.showToastMsg('身份证号码格式不正确');
|
||||
return;
|
||||
}
|
||||
|
||||
this.saving = true;
|
||||
try {
|
||||
const data = { ...this.formData, id: this.contactId };
|
||||
await athleteAPI.saveContact(data);
|
||||
uni.showToast({ title: '保存成功', icon: 'success' });
|
||||
setTimeout(() => { uni.navigateBack(); }, 1500);
|
||||
} catch (err) {
|
||||
console.error('保存联系人失败:', err);
|
||||
this.showToastMsg('保存失败,请重试');
|
||||
} finally {
|
||||
this.saving = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.add-contact-page {
|
||||
min-height: 100vh;
|
||||
background-color: #f5f5f5;
|
||||
padding-bottom: 200rpx;
|
||||
}
|
||||
|
||||
.form-container {
|
||||
background-color: #fff;
|
||||
margin: 30rpx;
|
||||
border-radius: 16rpx;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.form-item {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding: 35rpx 30rpx;
|
||||
border-bottom: 1rpx solid #f5f5f5;
|
||||
}
|
||||
|
||||
.form-item:last-child { border-bottom: none; }
|
||||
.switch-item { padding: 30rpx; }
|
||||
|
||||
.form-label {
|
||||
width: 180rpx;
|
||||
font-size: 30rpx;
|
||||
color: #333333;
|
||||
}
|
||||
|
||||
.form-value {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
.form-input {
|
||||
flex: 1;
|
||||
font-size: 30rpx;
|
||||
color: #333333;
|
||||
}
|
||||
|
||||
.placeholder { color: #cccccc; }
|
||||
.arrow { font-size: 40rpx; color: #cccccc; margin-left: 10rpx; }
|
||||
|
||||
.toast-message {
|
||||
position: fixed;
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
transform: translate(-50%, -50%);
|
||||
background-color: rgba(0, 0, 0, 0.7);
|
||||
color: #fff;
|
||||
padding: 30rpx 50rpx;
|
||||
border-radius: 16rpx;
|
||||
z-index: 9999;
|
||||
}
|
||||
|
||||
.toast-text { font-size: 28rpx; }
|
||||
|
||||
.btn-wrapper {
|
||||
position: fixed;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
padding: 30rpx;
|
||||
background-color: #f5f5f5;
|
||||
}
|
||||
|
||||
.btn {
|
||||
width: 100%;
|
||||
text-align: center;
|
||||
padding: 30rpx;
|
||||
border-radius: 12rpx;
|
||||
font-size: 32rpx;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.save-btn {
|
||||
background-color: #C93639;
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.save-btn.disabled {
|
||||
background-color: rgba(201, 54, 57, 0.5);
|
||||
}
|
||||
</style>
|
||||
@@ -98,22 +98,22 @@
|
||||
<view class="event-info-card">
|
||||
<view class="event-title">{{ eventInfo.title }}</view>
|
||||
<view class="divider"></view>
|
||||
<view class="info-item">
|
||||
<view class="info-item contact-item" @click="showContactPicker = true">
|
||||
<text class="label">地点:</text>
|
||||
<text class="value">{{ eventInfo.location }}</text>
|
||||
</view>
|
||||
<view class="info-item">
|
||||
<view class="info-item contact-item" @click="showContactPicker = true">
|
||||
<text class="label">比赛时间:</text>
|
||||
<text class="value">{{ eventInfo.matchTime }}</text>
|
||||
</view>
|
||||
<view class="info-item">
|
||||
<view class="info-item contact-item" @click="showContactPicker = true">
|
||||
<text class="label">报名项目:</text>
|
||||
<text class="value">{{ eventInfo.projects }}</text>
|
||||
</view>
|
||||
<view class="info-item">
|
||||
<view class="info-item contact-item" @click="showContactPicker = true">
|
||||
<text class="label">联系人:</text>
|
||||
<text class="value">{{ eventInfo.contact }}</text>
|
||||
<text class="edit-icon">📋</text>
|
||||
<text class="value" :class="{ placeholder: !selectedContact }">{{ selectedContact ? selectedContact.name + " " + selectedContact.phone : "请选择联系人" }}</text>
|
||||
<text class="arrow">›</text>
|
||||
</view>
|
||||
<view class="info-hint">(注意是否用此号码接收信息)</view>
|
||||
<view class="info-item participants-item">
|
||||
@@ -151,21 +151,21 @@
|
||||
<view class="event-info-card">
|
||||
<view class="event-title">{{ eventInfo.title }}</view>
|
||||
<view class="divider"></view>
|
||||
<view class="info-item">
|
||||
<view class="info-item contact-item" @click="showContactPicker = true">
|
||||
<text class="label">地点:</text>
|
||||
<text class="value">{{ eventInfo.location }}</text>
|
||||
</view>
|
||||
<view class="info-item">
|
||||
<view class="info-item contact-item" @click="showContactPicker = true">
|
||||
<text class="label">比赛时间:</text>
|
||||
<text class="value">{{ eventInfo.matchTime }}</text>
|
||||
</view>
|
||||
<view class="info-item">
|
||||
<view class="info-item contact-item" @click="showContactPicker = true">
|
||||
<text class="label">报名项目:</text>
|
||||
<text class="value">{{ eventInfo.projects }}</text>
|
||||
</view>
|
||||
<view class="info-item">
|
||||
<view class="info-item contact-item" @click="showContactPicker = true">
|
||||
<text class="label">联系人:</text>
|
||||
<text class="value">{{ eventInfo.contact }}</text>
|
||||
<text class="value" :class="{ placeholder: !selectedContact }">{{ selectedContact ? selectedContact.name + " " + selectedContact.phone : "请选择联系人" }}</text>
|
||||
</view>
|
||||
|
||||
<template v-if="!isTeamProject">
|
||||
@@ -211,6 +211,32 @@
|
||||
</scroll-view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 联系人选择弹窗 -->
|
||||
<view class="contact-modal" v-if="showContactPicker" @click="showContactPicker = false">
|
||||
<view class="modal-content" @click.stop>
|
||||
<view class="modal-header">
|
||||
<text class="modal-title">选择联系人</text>
|
||||
<text class="close-icon" @click="showContactPicker = false">✕</text>
|
||||
</view>
|
||||
<view class="add-contact-btn" @click="goToAddContact">
|
||||
<text class="add-icon">⊕</text>
|
||||
<text>新增联系人</text>
|
||||
</view>
|
||||
<scroll-view class="modal-body contact-list" scroll-y>
|
||||
<view class="contact-item" v-for="(item, index) in contactList" :key="index" @click="selectContact(item)">
|
||||
<view class="contact-info">
|
||||
<view class="contact-name">{{ item.name }}</view>
|
||||
<view class="contact-phone">{{ item.phone }}</view>
|
||||
</view>
|
||||
<view class="contact-check" v-if="selectedContact && selectedContact.id === item.id">✓</view>
|
||||
</view>
|
||||
<view class="empty-state" v-if="contactList.length === 0">
|
||||
<text class="empty-text">暂无联系人,请先新增</text>
|
||||
</view>
|
||||
</scroll-view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
@@ -240,6 +266,9 @@ export default {
|
||||
selectedPlayers: [],
|
||||
selectedTeams: [],
|
||||
showPlayerModal: false,
|
||||
showContactPicker: false,
|
||||
contactList: [],
|
||||
selectedContact: null,
|
||||
totalPrice: 0,
|
||||
registrationId: ''
|
||||
};
|
||||
@@ -290,6 +319,38 @@ export default {
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
// Contact methods
|
||||
async loadContactList() {
|
||||
try {
|
||||
const res = await athleteAPI.getContactList({ current: 1, size: 100 })
|
||||
this.contactList = (res.records || []).map(item => ({
|
||||
id: item.id,
|
||||
name: item.name,
|
||||
phone: item.phone,
|
||||
idCard: item.idCard
|
||||
}))
|
||||
// Auto select default contact if exists
|
||||
if (!this.selectedContact && this.contactList.length > 0) {
|
||||
const defaultContact = this.contactList.find(c => c.isDefault) || this.contactList[0]
|
||||
this.selectedContact = defaultContact
|
||||
}
|
||||
} catch (err) {
|
||||
console.error('加载联系人列表失败:', err)
|
||||
}
|
||||
},
|
||||
|
||||
selectContact(contact) {
|
||||
this.selectedContact = contact
|
||||
this.showContactPicker = false
|
||||
},
|
||||
|
||||
goToAddContact() {
|
||||
this.showContactPicker = false
|
||||
uni.navigateTo({
|
||||
url: '/pages/add-contact/add-contact'
|
||||
})
|
||||
},
|
||||
|
||||
async loadEventDetail(id) {
|
||||
try {
|
||||
const res = await competitionAPI.getCompetitionDetail(id)
|
||||
@@ -487,6 +548,7 @@ export default {
|
||||
}
|
||||
|
||||
this.totalPrice = this.calculateTotalPrice()
|
||||
this.loadContactList()
|
||||
this.$nextTick(() => { this.currentStep = 2 })
|
||||
},
|
||||
|
||||
@@ -518,7 +580,7 @@ export default {
|
||||
projectIds: this.selectedProjects.map(p => String(p.id)),
|
||||
teamIds: selected.map(t => String(t.id)),
|
||||
athleteIds: [],
|
||||
contactPhone: this.eventInfo.contact || '',
|
||||
contactPhone: this.selectedContact ? this.selectedContact.phone : '',
|
||||
totalAmount: parseFloat(this.totalPrice) || 0
|
||||
}
|
||||
} else {
|
||||
@@ -532,7 +594,7 @@ export default {
|
||||
competitionId: String(this.eventId),
|
||||
projectIds: this.selectedProjects.map(p => String(p.id)),
|
||||
athleteIds: selected.map(p => String(p.id)),
|
||||
contactPhone: this.eventInfo.contact || '',
|
||||
contactPhone: this.selectedContact ? this.selectedContact.phone : '',
|
||||
totalAmount: parseFloat(this.totalPrice) || 0
|
||||
}
|
||||
}
|
||||
@@ -1014,6 +1076,84 @@ export default {
|
||||
color: #C93639;
|
||||
margin-top: 10rpx;
|
||||
}
|
||||
|
||||
/* Contact Modal Styles */
|
||||
.contact-modal {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
background-color: rgba(0, 0, 0, 0.5);
|
||||
display: flex;
|
||||
align-items: flex-end;
|
||||
z-index: 1000;
|
||||
}
|
||||
|
||||
.contact-modal .modal-content {
|
||||
background-color: #fff;
|
||||
border-radius: 24rpx 24rpx 0 0;
|
||||
width: 100%;
|
||||
max-height: 70vh;
|
||||
}
|
||||
|
||||
.contact-modal .add-contact-btn {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
padding: 24rpx;
|
||||
border-bottom: 1rpx solid #eee;
|
||||
color: #C93639;
|
||||
font-size: 28rpx;
|
||||
}
|
||||
|
||||
.contact-modal .add-contact-btn .add-icon {
|
||||
margin-right: 10rpx;
|
||||
font-size: 32rpx;
|
||||
}
|
||||
|
||||
.contact-modal .contact-list {
|
||||
max-height: 50vh;
|
||||
}
|
||||
|
||||
.contact-modal .contact-item {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
padding: 24rpx 30rpx;
|
||||
border-bottom: 1rpx solid #f5f5f5;
|
||||
}
|
||||
|
||||
.contact-modal .contact-info {
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.contact-modal .contact-name {
|
||||
font-size: 30rpx;
|
||||
color: #333;
|
||||
margin-bottom: 8rpx;
|
||||
}
|
||||
|
||||
.contact-modal .contact-phone {
|
||||
font-size: 26rpx;
|
||||
color: #999;
|
||||
}
|
||||
|
||||
.contact-modal .contact-check {
|
||||
color: #C93639;
|
||||
font-size: 36rpx;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.contact-item.clickable,
|
||||
.info-item.contact-item {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.info-item .placeholder {
|
||||
color: #999;
|
||||
}
|
||||
|
||||
</style>
|
||||
|
||||
.empty-state {
|
||||
|
||||
@@ -138,7 +138,7 @@ export default {
|
||||
matchTime: this.formatTimeRange(startTime, endTime) ||
|
||||
item.matchTime || item.competitionTime || '待定',
|
||||
registerCount: item.registrationCount || item.registerCount || item.signUpCount || item.totalParticipants || '0',
|
||||
status: this.getStatus(item.status)
|
||||
status: this.getStatus(item.status, regEndTime)
|
||||
}
|
||||
})
|
||||
|
||||
@@ -174,12 +174,20 @@ export default {
|
||||
* @param {Number|String} status 状态码
|
||||
* @returns {String}
|
||||
*/
|
||||
getStatus(status) {
|
||||
getStatus(status, regEndTime) {
|
||||
// 根据后端状态码映射为前端需要的状态
|
||||
// 1: 报名中, 2: 进行中, 3: 已结束
|
||||
if (status === 3 || status === '3' || status === 'finished') {
|
||||
return 'finished'
|
||||
}
|
||||
// 根据报名结束时间判断是否已结束
|
||||
if (regEndTime) {
|
||||
const endDate = new Date(regEndTime)
|
||||
const now = new Date()
|
||||
if (now > endDate) {
|
||||
return 'finished'
|
||||
}
|
||||
}
|
||||
return 'open'
|
||||
},
|
||||
|
||||
|
||||
@@ -42,8 +42,8 @@
|
||||
<text class="value participants">{{ item.participants }}</text>
|
||||
</view>
|
||||
|
||||
<view class="event-footer" v-if="item.status === 'ongoing'">
|
||||
<view class="register-note">
|
||||
<view class="event-footer">
|
||||
<view class="register-note" v-if="item.status === 'ongoing'">
|
||||
<text>点击后进入【赛事详情】页面</text>
|
||||
</view>
|
||||
<view class="view-cert-btn" @click.stop="handleViewCert(item)">
|
||||
@@ -58,6 +58,26 @@
|
||||
<view class="empty-state" v-if="filteredList.length === 0">
|
||||
<text class="empty-text">暂无报名记录</text>
|
||||
</view>
|
||||
|
||||
<!-- 证件弹窗 -->
|
||||
<view class="cert-modal" v-if="showCertModal" @click="closeCertModal">
|
||||
<view class="cert-modal-content" @click.stop>
|
||||
<view class="cert-modal-header">
|
||||
<text class="cert-modal-title">参赛选手证件</text>
|
||||
<text class="cert-close-icon" @click="closeCertModal">✕</text>
|
||||
</view>
|
||||
<scroll-view class="cert-modal-body" scroll-y>
|
||||
<view class="cert-athlete-item" v-for="(athlete, index) in certAthleteList" :key="index">
|
||||
<view class="cert-athlete-name">{{ athlete.playerName }}</view>
|
||||
<view class="cert-athlete-info">性别:{{ athlete.gender === 1 ? '男' : '女' }}</view>
|
||||
<view class="cert-athlete-info">身份证:{{ athlete.idCard || '暂无' }}</view>
|
||||
</view>
|
||||
<view class="cert-empty" v-if="certAthleteList.length === 0">
|
||||
<text>暂无选手信息</text>
|
||||
</view>
|
||||
</scroll-view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
@@ -80,7 +100,9 @@ export default {
|
||||
current: 1,
|
||||
size: 20
|
||||
},
|
||||
hasMore: true
|
||||
hasMore: true,
|
||||
showCertModal: false,
|
||||
certAthleteList: []
|
||||
};
|
||||
},
|
||||
onLoad() {
|
||||
@@ -235,7 +257,8 @@ export default {
|
||||
) || '',
|
||||
projects: item.projectNames || this.formatProjects(item.projects) || '',
|
||||
contact: item.contactPhone || item.contactPerson || '',
|
||||
participants: item.athleteNames || `${item.totalParticipants || 0}人`
|
||||
participants: item.athleteNames || `${item.totalParticipants || 0}人`,
|
||||
athleteList: item.athleteList || []
|
||||
}
|
||||
},
|
||||
|
||||
@@ -322,10 +345,20 @@ export default {
|
||||
});
|
||||
},
|
||||
handleViewCert(item) {
|
||||
uni.showToast({
|
||||
title: '查看证件',
|
||||
icon: 'none'
|
||||
});
|
||||
// Get athlete list from the item
|
||||
if (item.athleteList && item.athleteList.length > 0) {
|
||||
this.certAthleteList = item.athleteList;
|
||||
this.showCertModal = true;
|
||||
} else {
|
||||
uni.showToast({
|
||||
title: '暂无选手证件信息',
|
||||
icon: 'none'
|
||||
});
|
||||
}
|
||||
},
|
||||
closeCertModal() {
|
||||
this.showCertModal = false;
|
||||
this.certAthleteList = [];
|
||||
}
|
||||
}
|
||||
};
|
||||
@@ -446,4 +479,77 @@ export default {
|
||||
font-size: 28rpx;
|
||||
color: #999999;
|
||||
}
|
||||
|
||||
/* Cert Modal Styles */
|
||||
.cert-modal {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
background-color: rgba(0, 0, 0, 0.5);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
z-index: 1000;
|
||||
}
|
||||
|
||||
.cert-modal-content {
|
||||
background-color: #fff;
|
||||
border-radius: 16rpx;
|
||||
width: 85%;
|
||||
max-height: 70vh;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.cert-modal-header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
padding: 30rpx;
|
||||
border-bottom: 1rpx solid #eee;
|
||||
}
|
||||
|
||||
.cert-modal-title {
|
||||
font-size: 32rpx;
|
||||
font-weight: bold;
|
||||
color: #333;
|
||||
}
|
||||
|
||||
.cert-close-icon {
|
||||
font-size: 36rpx;
|
||||
color: #999;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.cert-modal-body {
|
||||
max-height: 50vh;
|
||||
padding: 20rpx 30rpx;
|
||||
}
|
||||
|
||||
.cert-athlete-item {
|
||||
padding: 20rpx;
|
||||
background-color: #f9f9f9;
|
||||
border-radius: 12rpx;
|
||||
margin-bottom: 20rpx;
|
||||
}
|
||||
|
||||
.cert-athlete-name {
|
||||
font-size: 30rpx;
|
||||
font-weight: bold;
|
||||
color: #333;
|
||||
margin-bottom: 10rpx;
|
||||
}
|
||||
|
||||
.cert-athlete-info {
|
||||
font-size: 26rpx;
|
||||
color: #666;
|
||||
margin-bottom: 6rpx;
|
||||
}
|
||||
|
||||
.cert-empty {
|
||||
text-align: center;
|
||||
padding: 40rpx;
|
||||
color: #999;
|
||||
}
|
||||
</style>
|
||||
|
||||
Reference in New Issue
Block a user