382 lines
10 KiB
Vue
382 lines
10 KiB
Vue
<template>
|
||
<view class="ciy-page">
|
||
<!-- 顶部导航栏:复用框架标题样式 -->
|
||
<view class="ciy-title mk rel bg3">
|
||
<text class="abs l1 t0 txt9 tran5" @tap="goBack">← 返回</text>
|
||
<view class="title txt9">{{isEdit ? '编辑成员' : '新增成员'}}</view>
|
||
<view class="right">
|
||
<text class="btn man sm cc px3" @tap="submitForm">{{isEdit ? '保存' : '提交'}}</text>
|
||
</view>
|
||
</view>
|
||
|
||
<!-- 主体内容区:滚动表单 -->
|
||
<view class="main overflow-auto">
|
||
<!-- 表单容器:复用框架卡片/间距样式 -->
|
||
<view class="ciy-card my3 mx4">
|
||
<!-- 基础信息标题:复用框架标题样式 -->
|
||
<view class="title mk">基础信息</view>
|
||
<view class="content">
|
||
<!-- 姓名输入项:复用框架表单样式 -->
|
||
<view class="ciy-form char4 mb3">
|
||
<label class="imp txt7">姓名:</label>
|
||
<view>
|
||
<input
|
||
class="ciy-edit txt7 bg4 py2 px3 rounded-md w-full"
|
||
v-model="formData.name"
|
||
placeholder="请输入姓名"
|
||
/>
|
||
</view>
|
||
</view>
|
||
|
||
<!-- 手机号输入项:复用框架表单样式 -->
|
||
<view class="ciy-form char4 mb3">
|
||
<label class="imp txt7">手机号:</label>
|
||
<view>
|
||
<input
|
||
class="ciy-edit txt7 bg4 py2 px3 rounded-md w-full"
|
||
v-model="formData.mobile"
|
||
type="number"
|
||
placeholder="请输入手机号"
|
||
:disabled="isEdit"
|
||
/>
|
||
</view>
|
||
</view>
|
||
|
||
<!-- 头衔选择项:复用框架表单样式 -->
|
||
<view class="ciy-form char4 mb3">
|
||
<label class="imp txt7">头衔:</label>
|
||
<view>
|
||
<picker
|
||
class="bg4 py2 px3 rounded-md w-full txt7"
|
||
:range="titleList"
|
||
range-key="name"
|
||
:value="titleIndex"
|
||
@change="handleTitleChange"
|
||
>
|
||
<view class="flex justify-between items-center">
|
||
<text>{{titleIndex >= 0 ? titleList[titleIndex].name : '请选择头衔'}}</text>
|
||
<text class="txt3">▼</text>
|
||
</view>
|
||
</picker>
|
||
</view>
|
||
</view>
|
||
|
||
<!-- 状态选择项:复用框架表单样式 -->
|
||
<view class="ciy-form char4 mb3">
|
||
<label class="imp txt7">状态:</label>
|
||
<view>
|
||
<picker
|
||
class="bg4 py2 px3 rounded-md w-full txt7"
|
||
:range="statusList"
|
||
range-key="name"
|
||
:value="statusIndex"
|
||
@change="handleStatusChange"
|
||
>
|
||
<view class="flex justify-between items-center">
|
||
<text>{{statusIndex >= 0 ? statusList[statusIndex].name : '请选择状态'}}</text>
|
||
<text class="txt3">▼</text>
|
||
</view>
|
||
</picker>
|
||
</view>
|
||
</view>
|
||
|
||
<!-- 性别选择项:复用框架表单样式 -->
|
||
<view class="ciy-form char4 mb3">
|
||
<label class="txt7">性别:</label>
|
||
<view>
|
||
<picker
|
||
class="bg4 py2 px3 rounded-md w-full txt7"
|
||
:range="sexList"
|
||
range-key="name"
|
||
:value="sexIndex"
|
||
@change="handleSexChange"
|
||
>
|
||
<view class="flex justify-between items-center">
|
||
<text>{{sexIndex >= 0 ? sexList[sexIndex].name : '请选择性别'}}</text>
|
||
<text class="txt3">▼</text>
|
||
</view>
|
||
</picker>
|
||
</view>
|
||
</view>
|
||
|
||
<!-- 邮箱输入项:复用框架表单样式 -->
|
||
<view class="ciy-form char4 mb3">
|
||
<label class="txt7">邮箱:</label>
|
||
<view>
|
||
<input
|
||
class="ciy-edit txt7 bg4 py2 px3 rounded-md w-full"
|
||
v-model="formData.email"
|
||
type="email"
|
||
placeholder="请输入邮箱"
|
||
/>
|
||
</view>
|
||
</view>
|
||
</view>
|
||
</view>
|
||
|
||
<!-- 密码设置:仅新增显示,复用框架卡片样式 -->
|
||
<view v-if="!isEdit" class="ciy-card my3 mx4">
|
||
<view class="title mk">密码设置</view>
|
||
<view class="content">
|
||
<!-- 初始密码 -->
|
||
<view class="ciy-form char4 mb3">
|
||
<label class="imp txt7">初始密码:</label>
|
||
<view>
|
||
<input
|
||
class="ciy-edit txt7 bg4 py2 px3 rounded-md w-full"
|
||
v-model="formData.pass"
|
||
type="password"
|
||
placeholder="请设置初始密码(不少于6位)"
|
||
/>
|
||
</view>
|
||
</view>
|
||
|
||
<!-- 确认密码 -->
|
||
<view class="ciy-form char4 mb3">
|
||
<label class="imp txt7">确认密码:</label>
|
||
<view>
|
||
<input
|
||
class="ciy-edit txt7 bg4 py2 px3 rounded-md w-full"
|
||
v-model="formData.pass2"
|
||
type="password"
|
||
placeholder="请再次输入密码"
|
||
/>
|
||
</view>
|
||
</view>
|
||
</view>
|
||
</view>
|
||
</view>
|
||
|
||
<!-- 底部固定区 -->
|
||
<view class="ciy-bottom"></view>
|
||
</view>
|
||
</template>
|
||
|
||
<script>
|
||
// 优先使用相对路径引入md5
|
||
import md5 from '../../util/md5.js';
|
||
|
||
export default {
|
||
data() {
|
||
return {
|
||
isEdit: false, // 是否编辑模式
|
||
formData: {
|
||
id: 0,
|
||
name: '',
|
||
mobile: '',
|
||
usertitle: 1, // 默认负责人
|
||
status: 1, // 默认在册
|
||
sex: 0, // 默认未知
|
||
email: '',
|
||
pass: '',
|
||
pass2: ''
|
||
},
|
||
// 头衔列表
|
||
titleList: [
|
||
{id: 1, name: '负责人'},
|
||
{id: 2, name: '科研秘书'},
|
||
{id: 3, name: '在册成员'},
|
||
{id: 4, name: '历史成员'},
|
||
{id: 5, name: '外部成员'}
|
||
],
|
||
titleIndex: 0, // 默认选中第一个
|
||
// 状态列表
|
||
statusList: [
|
||
{id: 1, name: '在册'},
|
||
{id: 2, name: '历史'}
|
||
],
|
||
statusIndex: 0, // 默认选中第一个
|
||
// 性别列表
|
||
sexList: [
|
||
{id: 0, name: '未知'},
|
||
{id: 1, name: '男'},
|
||
{id: 2, name: '女'}
|
||
],
|
||
sexIndex: 0, // 默认选中第一个
|
||
submitting: false // 提交状态
|
||
};
|
||
},
|
||
onLoad(options) {
|
||
if (options.id && options.id > 0) {
|
||
this.isEdit = true;
|
||
this.formData.id = parseInt(options.id);
|
||
this.getMemberDetail();
|
||
}
|
||
},
|
||
methods: {
|
||
// 返回上一页
|
||
goBack() {
|
||
uni.navigateBack();
|
||
},
|
||
|
||
// 获取成员详情(编辑时)
|
||
async getMemberDetail() {
|
||
try {
|
||
const [err, res] = await uni.request({
|
||
url: '/ambap/member.php?act=member.detail',
|
||
method: 'POST',
|
||
data: { id: this.formData.id }
|
||
});
|
||
|
||
if (err) throw new Error('加载详情失败');
|
||
const result = res.data || {};
|
||
|
||
if (result.code === 1) {
|
||
const data = result.data;
|
||
this.formData = { ...this.formData, ...data };
|
||
// 兼容找不到匹配项的情况
|
||
this.titleIndex = this.titleList.findIndex(item => item.id === data.usertitle) || 0;
|
||
this.statusIndex = this.statusList.findIndex(item => item.id === data.status) || 0;
|
||
this.sexIndex = this.sexList.findIndex(item => item.id === data.sex) || 0;
|
||
} else {
|
||
uni.showToast({ title: result.errmsg || '成员不存在', icon: 'none' });
|
||
this.goBack();
|
||
}
|
||
} catch (err) {
|
||
uni.showToast({ title: '加载详情失败', icon: 'none' });
|
||
console.error('获取详情失败:', err);
|
||
this.goBack();
|
||
}
|
||
},
|
||
|
||
// 头衔选择
|
||
handleTitleChange(e) {
|
||
this.titleIndex = e.detail.value;
|
||
this.formData.usertitle = this.titleList[this.titleIndex].id;
|
||
},
|
||
|
||
// 状态选择
|
||
handleStatusChange(e) {
|
||
this.statusIndex = e.detail.value;
|
||
this.formData.status = this.statusList[this.statusIndex].id;
|
||
},
|
||
|
||
// 性别选择
|
||
handleSexChange(e) {
|
||
this.sexIndex = e.detail.value;
|
||
this.formData.sex = this.sexList[this.sexIndex].id;
|
||
},
|
||
|
||
// 表单验证
|
||
validateForm() {
|
||
// 姓名验证
|
||
if (!this.formData.name.trim()) {
|
||
uni.showToast({ title: '请输入姓名', icon: 'none' });
|
||
return false;
|
||
}
|
||
// 手机号验证
|
||
const mobileReg = /^1[3-9]\d{9}$/;
|
||
if (!this.formData.mobile) {
|
||
uni.showToast({ title: '请输入手机号', icon: 'none' });
|
||
return false;
|
||
}
|
||
if (!mobileReg.test(this.formData.mobile)) {
|
||
uni.showToast({ title: '手机号格式错误', icon: 'none' });
|
||
return false;
|
||
}
|
||
// 头衔验证
|
||
if (this.titleIndex === -1) {
|
||
uni.showToast({ title: '请选择头衔', icon: 'none' });
|
||
return false;
|
||
}
|
||
// 状态验证
|
||
if (this.statusIndex === -1) {
|
||
uni.showToast({ title: '请选择状态', icon: 'none' });
|
||
return false;
|
||
}
|
||
// 新增时验证密码
|
||
if (!this.isEdit) {
|
||
if (!this.formData.pass) {
|
||
uni.showToast({ title: '请设置初始密码', icon: 'none' });
|
||
return false;
|
||
}
|
||
if (this.formData.pass.length < 6) {
|
||
uni.showToast({ title: '密码不少于6位', icon: 'none' });
|
||
return false;
|
||
}
|
||
if (this.formData.pass !== this.formData.pass2) {
|
||
uni.showToast({ title: '两次密码不一致', icon: 'none' });
|
||
return false;
|
||
}
|
||
}
|
||
return true;
|
||
},
|
||
|
||
// 提交表单
|
||
async submitForm() {
|
||
if (this.submitting) return;
|
||
if (!this.validateForm()) return;
|
||
|
||
this.submitting = true;
|
||
try {
|
||
// 构造提交数据
|
||
const submitData = { ...this.formData };
|
||
// 新增时加密密码(兼容md5不同导出格式)
|
||
if (!this.isEdit) {
|
||
const tokenSalt = getApp()?.globalData?.tokensalt || 'default_salt';
|
||
submitData.password = typeof md5 === 'function'
|
||
? md5(submitData.pass + tokenSalt)
|
||
: md5.md5(submitData.pass + tokenSalt);
|
||
delete submitData.pass;
|
||
delete submitData.pass2;
|
||
}
|
||
|
||
// 调用后端接口
|
||
const [err, res] = await uni.request({
|
||
url: this.isEdit ? '/ambap/member.php?act=member.edit' : '/ambap/member.php?act=member.add',
|
||
method: 'POST',
|
||
data: submitData
|
||
});
|
||
|
||
if (err) throw new Error('提交失败,请检查网络');
|
||
const result = res.data || {};
|
||
|
||
if (result.code === 1) {
|
||
uni.showToast({ title: this.isEdit ? '修改成功' : '新增成功', icon: 'success' });
|
||
// 返回列表页并刷新
|
||
setTimeout(() => {
|
||
uni.navigateBack({
|
||
success: () => {
|
||
const pages = getCurrentPages();
|
||
const listPage = pages[pages.length - 2];
|
||
if (listPage && typeof listPage.refreshList === 'function') {
|
||
listPage.refreshList();
|
||
}
|
||
}
|
||
});
|
||
}, 1000);
|
||
} else {
|
||
uni.showToast({ title: result.errmsg || '操作失败', icon: 'none' });
|
||
}
|
||
} catch (err) {
|
||
uni.showToast({ title: err.message || '提交失败', icon: 'none' });
|
||
console.error('提交表单失败:', err);
|
||
} finally {
|
||
this.submitting = false;
|
||
}
|
||
}
|
||
}
|
||
};
|
||
</script>
|
||
|
||
<style scoped>
|
||
/* 仅补充框架未覆盖的极少量通用样式 */
|
||
.rounded-md {
|
||
border-radius: 0.3rem;
|
||
}
|
||
.w-full {
|
||
width: 100%;
|
||
}
|
||
.justify-between {
|
||
justify-content: space-between;
|
||
}
|
||
.items-center {
|
||
align-items: center;
|
||
}
|
||
.overflow-auto {
|
||
overflow: auto;
|
||
}
|
||
.mb3 {
|
||
margin-bottom: 0.75rem;
|
||
}
|
||
</style> |