Compare commits

...

2 Commits

Author SHA1 Message Date
ryx 2b53f1cf47 改2 2026-01-26 17:45:00 +08:00
ryx 3e61a51ad8 改1 2026-01-26 17:44:49 +08:00
12 changed files with 771 additions and 805 deletions

View File

@ -1,6 +1,7 @@
<template> <template>
<view :animation="anidataauth" class="auth"> <view :animation="anidataauth" class="auth">
<view class="swiper" :style="{transform: 'translateX(' + pg + 'vw)',height:height}"> <view class="swiper" :style="{transform: 'translateX(' + pg + 'vw)',height:height}">
<!-- 注册页面 -->
<view class="content"> <view class="content">
<view class="title"> <view class="title">
<ciy-gesture @toleft="gopg(1)" class="mid" style="letter-spacing: 1em;">{{lang('login.tabreg')}}</ciy-gesture> <ciy-gesture @toleft="gopg(1)" class="mid" style="letter-spacing: 1em;">{{lang('login.tabreg')}}</ciy-gesture>
@ -42,6 +43,7 @@
</form> </form>
</view> </view>
<!-- 登录页面 -->
<view class="content"> <view class="content">
<view class="title"> <view class="title">
<view @tap="gopg(0)" style="padding-right:2em;">{{lang('login.tabreg')}}</view> <view @tap="gopg(0)" style="padding-right:2em;">{{lang('login.tabreg')}}</view>
@ -85,6 +87,7 @@
</form> </form>
</view> </view>
<!-- 忘记密码页面 -->
<view class="content"> <view class="content">
<view class="title"> <view class="title">
<view @tap="gopg(0)">{{lang('login.tabreg')}}</view> <view @tap="gopg(0)">{{lang('login.tabreg')}}</view>
@ -102,7 +105,7 @@
<view class="ciy-form"> <view class="ciy-form">
<label>验证码</label> <label>验证码</label>
<view> <view>
<ciy-capcode hasmore name="capsms" btntxt="发送短信" :account="forgetmobile" :func="smsfunc" placeholder="请输入验证码"></ciy-capcode> <ciy-capcode hasmore name="captcha" btntxt="发送短信" :account="forgetmobile" :func="smsfunc" placeholder="请输入验证码"></ciy-capcode>
</view> </view>
</view> </view>
<view class="ciy-form"> <view class="ciy-form">
@ -168,7 +171,6 @@
.auth { .auth {
position: fixed; position: fixed;
z-index: 50002; z-index: 50002;
/*51*/
bottom: -2em; bottom: -2em;
left: 0; left: 0;
right: 0; right: 0;
@ -178,7 +180,6 @@
.authbg { .authbg {
position: fixed; position: fixed;
z-index: 50001; z-index: 50001;
/*50*/
top: 0; top: 0;
bottom: 0; bottom: 0;
left: -0.5em; left: -0.5em;
@ -204,6 +205,7 @@
box-shadow: 2px 2px 20px -10px var(--bg9); box-shadow: 2px 2px 20px -10px var(--bg9);
} }
</style> </style>
<script> <script>
import md5 from '@/util/md5.js'; import md5 from '@/util/md5.js';
export default { export default {
@ -215,7 +217,7 @@
user: '', user: '',
pass: '', pass: '',
xieyi: false, xieyi: false,
pg: -100, //-100 pg: -100,
ver: 6, ver: 6,
height: '28em', height: '28em',
tusers: [], tusers: [],
@ -226,10 +228,9 @@
options: { options: {
virtualHost: true virtualHost: true
}, },
watch: {},
computed: {},
mounted() {}, mounted() {},
methods: { methods: {
//
async Open(authcb, must) { async Open(authcb, must) {
this.authcb = authcb; this.authcb = authcb;
if (!must) { if (!must) {
@ -249,7 +250,7 @@
onlyAuthorize: true onlyAuthorize: true
}); });
var retjson = await this.callfunc({ var retjson = await this.callfunc({
func: 'login.wx_autouser', func: 'login.json_wx_autouser',
loadhide: true, loadhide: true,
data: { data: {
code: res.code, code: res.code,
@ -262,6 +263,7 @@
return; return;
//#endif //#endif
} }
//
var animation = uni.createAnimation({ var animation = uni.createAnimation({
timingFunction: 'ease' timingFunction: 'ease'
}); });
@ -270,6 +272,7 @@
duration: 700 duration: 700
}); });
this.anidataauth = animation.export(); this.anidataauth = animation.export();
var animation = uni.createAnimation({ var animation = uni.createAnimation({
timingFunction: 'ease' timingFunction: 'ease'
}); });
@ -278,12 +281,16 @@
duration: 400 duration: 400
}); });
this.anidatabg = animation.export(); this.anidatabg = animation.export();
this.user = this.getstorage('login_mb'); this.user = this.getstorage('login_mb');
this.smsfunc = 'login.sendsms'; this.smsfunc = 'login.json_sendsms';
}, },
//
async submitlogin(e) { async submitlogin(e) {
var app = getApp(); var app = getApp();
var post = e.detail.value; var post = e.detail.value;
if (post.user.length > 0) if (post.user.length > 0)
this.setstorage('login_mb', post.user); this.setstorage('login_mb', post.user);
if (post.user == '') if (post.user == '')
@ -292,23 +299,33 @@
return this.toast('请填写密码'); return this.toast('请填写密码');
if (!this.xieyi && await this.askmsg('是否阅读并同意协议?', '同意') != 'ok') if (!this.xieyi && await this.askmsg('是否阅读并同意协议?', '同意') != 'ok')
return; return;
//
post.auth = (new Date()).getTime(); post.auth = (new Date()).getTime();
post.appcid = app.globalData._appcid; post.appcid = app.globalData._appcid;
var epass = md5.md5(post.pass + app.globalData.tokensalt);
post.pass = md5.md5(epass + post.auth); // md5(MD5 + auth)
//._from = app.globalData._sysinfo; var userPassMd5 = md5.md5(post.pass);
post.pass = md5.md5(userPassMd5 + post.auth);
//
var retjson = await this.callfunc({ var retjson = await this.callfunc({
func: 'login.login_mobile', // login.login func: 'login.json_login_mobile',
data: post data: post
}); });
if (retjson.code != 1) if (retjson.code != 1)
return this.toast(retjson.errmsg); return this.toast(retjson.errmsg);
this.setstorage('_dbgs', retjson.dbgs); this.setstorage('_dbgs', retjson.dbgs);
this.tologin(retjson); this.tologin(retjson);
}, },
//
async submitreg(e) { async submitreg(e) {
var app = getApp(); var app = getApp();
var post = e.detail.value; var post = e.detail.value;
if (post.user == '') if (post.user == '')
return this.toast('请填写手机号'); return this.toast('请填写手机号');
if (post.pass == '') if (post.pass == '')
@ -317,24 +334,32 @@
return this.toast('两次密码输入不同'); return this.toast('两次密码输入不同');
if (!this.xieyi && await this.askmsg('是否阅读并同意协议?', '同意') != 'ok') if (!this.xieyi && await this.askmsg('是否阅读并同意协议?', '同意') != 'ok')
return; return;
post.upid = app.getstorage('upid'); post.upid = app.getstorage('upid');
post.appcid = app.globalData._appcid; post.appcid = app.globalData._appcid;
post.pass = md5.md5(post.pass + app.globalData.tokensalt); // MD5()
post.pass = md5.md5(post.pass);
post.pass2 = ''; post.pass2 = '';
//._from = app.globalData._sysinfo;
//
var retjson = await this.callfunc({ var retjson = await this.callfunc({
func: 'login.reg_mobile', // login.reg func: 'login.json_reg_mobile',
data: post data: post
}); });
if (retjson.code != 1) if (retjson.code != 1)
return this.toast(retjson.errmsg); return this.toast(retjson.errmsg);
this.setstorage('login_mb', post.user); this.setstorage('login_mb', post.user);
this.tologin(retjson); this.tologin(retjson);
this.toast('注册成功,已自动登录'); this.toast('注册成功,已自动登录');
}, },
//
async submitforget(e) { async submitforget(e) {
var app = getApp(); var app = getApp();
var post = e.detail.value; var post = e.detail.value;
if (post.user == '') if (post.user == '')
return this.toast('请填写手机号'); return this.toast('请填写手机号');
if (post.captcha == '') if (post.captcha == '')
@ -343,16 +368,24 @@
return this.toast('请填写密码'); return this.toast('请填写密码');
if (post.pass != post.pass2) if (post.pass != post.pass2)
return this.toast('两次密码输入不同'); return this.toast('两次密码输入不同');
post.pass = md5.md5(post.pass + app.globalData.tokensalt);
// MD5()
post.pass = md5.md5(post.pass);
//
var retjson = await this.callfunc({ var retjson = await this.callfunc({
func: 'login.forgetpass', // login.reg func: 'login.json_forgetpass',
data: post data: post
}); });
if (retjson.code != 1) if (retjson.code != 1)
return this.toast(retjson.errmsg); return this.toast(retjson.errmsg);
this.tologin(retjson); this.tologin(retjson);
this.toast('密码找回成功,已自动登录'); this.toast('密码找回成功,已自动登录');
}, },
//
tologin(json) { tologin(json) {
var app = getApp(); var app = getApp();
var auth = app.setuserstorage(json); var auth = app.setuserstorage(json);
@ -361,9 +394,13 @@
this.authcb = null; this.authcb = null;
this.close(); this.close();
}, },
//
gopg(idx) { gopg(idx) {
this.pg = idx * -100; this.pg = idx * -100;
}, },
//
close() { close() {
if (this.authcb != null) if (this.authcb != null)
this.authcb({ this.authcb({
@ -372,6 +409,7 @@
} }
}); });
this.authcb = null; this.authcb = null;
var animation = uni.createAnimation({ var animation = uni.createAnimation({
timingFunction: 'ease' timingFunction: 'ease'
}); });
@ -380,6 +418,7 @@
duration: 1000 duration: 1000
}); });
this.anidataauth = animation.export(); this.anidataauth = animation.export();
var animation = uni.createAnimation({ var animation = uni.createAnimation({
timingFunction: 'ease' timingFunction: 'ease'
}); });
@ -389,6 +428,8 @@
}); });
this.anidatabg = animation.export(); this.anidatabg = animation.export();
}, },
//
async showver(e) { async showver(e) {
this.ver--; this.ver--;
if (this.ver !== 0) if (this.ver !== 0)
@ -396,17 +437,94 @@
var app = getApp(); var app = getApp();
if (app.globalData._wxenv == 'release') if (app.globalData._wxenv == 'release')
return; return;
var retjson = await this.callfunc({ var retjson = await this.callfunc({
func: 'login.debug_list', func: 'login.json_debug_list',
data: {} data: {}
}); });
this.tusers = retjson.list; this.tusers = retjson.list;
}, },
//
setdbg(idx) { setdbg(idx) {
this.xieyi = true; this.xieyi = true;
this.user = this.tusers[idx].user; this.user = this.tusers[idx].user;
this.pass = this.tusers[idx].pass; this.pass = this.tusers[idx].pass;
}, },
//
getme() {
return uni.getStorageSync('me') || {id: 0};
},
//
getstorage(key) {
return uni.getStorageSync(key) || '';
},
//
setstorage(key, value) {
uni.setStorageSync(key, value);
},
//
toint(val) {
return parseInt(val) || 0;
},
//
toast(msg) {
uni.showToast({
title: msg,
icon: 'none',
duration: 2000
});
},
//
askmsg(content, confirmText = '确定') {
return new Promise((resolve) => {
uni.showModal({
title: '提示',
content: content,
confirmText: confirmText,
success: (res) => {
resolve(res.confirm ? 'ok' : 'cancel');
}
});
});
},
//
async callfunc(options) {
return new Promise((resolve) => {
uni.request({
url: 'http://localhost:5173/ambap/login.php', //
method: 'POST',
data: {
act: options.func,
...options.data
},
success: (res) => {
resolve(res.data || {code: 0, errmsg: '接口返回异常'});
},
fail: (err) => {
this.toast('网络请求失败');
resolve({code: 0, errmsg: '网络错误'});
}
});
});
},
//
gourl(e) {
var url = e.currentTarget.dataset.url;
if (url) {
uni.navigateTo({
url: url
});
}
}
} }
} }
</script> </script>

View File

@ -412,23 +412,15 @@
] ]
}, },
{ {
"root": "pages/lab", "root": "pages/lab",
"pages": [ "pages": [
{ {
"path": "userlist", "path": "userlist",
"style": { "style": {
"navigationBarTitleText": "成员管理", // "enablePullDownRefresh": true
"enablePullDownRefresh": true }
} }
}, ]
// lab }
{
"path": "useredit",
"style": {
"navigationBarTitleText": "添加成员"
}
}
]
}
] ]
} }

View File

@ -1,382 +0,0 @@
<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>

View File

@ -1,271 +1,280 @@
<template> <template>
<view class="ciy-page"> <view class="container">
<!-- 顶部导航栏复用框架标题样式 + 返回首页按钮 --> <!-- 搜索栏按姓名/头衔搜索 -->
<view class="ciy-title mk rel bg3"> <view class="search my2">
<text class="abs l1 t0 txt9 tran5" @tap="goToHome"> 首页</text> <div class="flex flex-center">
<view class="title txt9">成员管理</view> <input
<view class="right"></view> type="text"
</view> v-model="searchKey"
placeholder="请输入姓名/头衔搜索"
class="flex1 px2 py1"
@confirm="getList"
/>
<button class="btn man ml2" @click="getList">搜索</button>
</div>
</view>
<!-- 主体内容区 --> <!-- 新增按钮 -->
<view class="main"> <button class="btn succ my2" @click="goToEdit">新增成员</button>
<!-- 搜索+新增区域复用框架布局/按钮样式 -->
<view class="flex flex-center px4 py2 bg1">
<!-- 搜索框复用框架背景/内边距样式 -->
<view class="flex1 bg4 py1 px3 rounded-lg flex flex-center">
<text class="txt3 mr2">🔍</text>
<input
class="flex1 ciy-edit txt7"
v-model="searchKey"
placeholder="按姓名/头衔搜索"
@input="handleSearch"
/>
</view>
<!-- 新增按钮复用框架btn样式 -->
<view class="btn man cc ml3 sm" @tap="goToUserEdit">
<text class="mr1">+</text>
<text>新增</text>
</view>
</view>
<!-- 分类标签栏复用框架滚动/布局样式 --> <!-- 成员列表 -->
<scroll-view scroll-x class="bg1"> <div class="table bg1 rounded">
<view class="flex px4 py2"> <!-- 表头 -->
<view <div class="flex bg5 txt6 py2 px2">
class="px3 py1 mx1 rounded-lg tran5" <div class="col-3 txt-center">头像</div>
v-for="(tab, idx) in tabs" <div class="col-4 txt-center">姓名</div>
:key="idx" <div class="col-4 txt-center">手机号</div>
:class="[activeTab === idx ? 'man txt-white' : 'bg4 txt6']" <div class="col-4 txt-center">头衔</div>
@tap="switchTab(idx)" <div class="col-4 txt-center">状态</div>
> <div class="col-3 txt-center">性别</div>
<text>{{tab.name}}</text> <div class="col-3 txt-center">学历</div>
</view> <div class="col-3 txt-center">操作</div>
</view> </div>
</scroll-view>
<!-- 成员列表区域复用框架网格/卡片样式 --> <!-- 列表内容 -->
<scroll-view <div class="list" v-if="list.length > 0">
class="flex1" <div
scroll-y class="flex py2 px2 border-b border-bg6"
@scrolltolower="loadMore" v-for="item in list"
refresher-enabled="true" :key="item.id"
@refresherrefresh="refreshList" >
> <div class="col-3 txt-center">
<!-- 成员网格复用框架九宫格样式 --> <image :src="item.avatar" mode="aspectFill" class="w-10 h-10 rounded-full"></image>
<view class="ciy-grid grid3 px4 py3 bg4"> </div>
<!-- 成员卡片复用框架列表/背景样式 --> <div class="col-4 txt-center">{{ item.name }}</div>
<view <div class="col-4 txt-center">{{ item.mobile }}</div>
class="grid my2" <div class="col-4 txt-center">{{ getTitleText(item.usertitle) }}</div>
v-for="(item, idx) in filterMembers" <div class="col-4 txt-center">
:key="item.id" <span :class="getStatusTagClass(item.stpstatus)">{{ getStatusText(item.stpstatus) }}</span>
@tap="goToUserEdit(item.id)" </div>
> <div class="col-3 txt-center">{{ getSexText(item.sex) }}</div>
<view class="bg1 rounded-lg p3 shadow-sm flex flexcol items-center"> <div class="col-3 txt-center">{{ getEducationText(item.education) }}</div>
<!-- 头像 --> <div class="col-3 txt-center flex flex-center justify-center gap2">
<image <button class="btn def sm" @click.stop="goToEdit(item.id)">编辑</button>
class="w12 h12 rounded-full mb2" <button class="btn dag sm" @click.stop="delMember(item.id)">删除</button>
:src="item.avatar || '/static/avatar-default.png'" <button
mode="aspectFill" class="btn sm"
@error="handleImgError($event)" :class="item.stpstatus === 30 ? 'warn' : 'succ'"
/> @click.stop="auditMember(item.id, item.stpstatus === 30 ? 40 : 30)"
<!-- 姓名 --> >
<text class="txt8 txt-lg txt-wb">{{item.name}}</text> {{ item.stpstatus === 30 ? '设为历史' : '设为在册' }}
<!-- 头衔 --> </button>
<text class="txt5 txt-sm mt1">{{getTitleName(item.usertitle)}}</text> </div>
<!-- 负责人标签复用框架警示样式 --> </div>
<text v-if="item.isLeader" class="warn txt-xs px2 py05 rounded mt1">负责人</text> </div>
</view>
</view>
</view>
<!-- 空列表提示复用框架提示样式 --> <!-- 空数据提示 -->
<view v-if="filterMembers.length === 0" class="ciy-tip txt-center py4"> <div class="txt-center py10 txt3" v-if="list.length === 0">
<text class="txt6">暂无{{tabs[activeTab].name}}类成员</text> 暂无成员数据
<view class="btn succ sm cc mt3" @tap="goToUserEdit"> </div>
<text>立即添加</text> </div>
</view>
</view>
<!-- 加载更多复用框架文字/间距样式 --> <!-- 分页 -->
<view v-if="hasMore && filterMembers.length > 0" class="txt-center py3 txt4"> <div class="table page flex justify-end mt2" v-if="total > pageSize">
<text>加载更多...</text> <button
</view> class="btn def sm mr1"
</scroll-view> @click="page--; getList()"
</view> :disabled="page <= 1"
>上一页</button>
<!-- 底部固定区框架默认 --> <span class="px2">{{ page }} / {{ Math.ceil(total / pageSize) }}</span>
<view class="ciy-bottom"></view> <button
</view> class="btn def sm ml1"
@click="page++; getList()"
:disabled="page >= Math.ceil(total / pageSize)"
>下一页</button>
</div>
</view>
</template> </template>
<script> <script>
export default { export default {
data() { data() {
return { return {
searchKey: '', // list: [], //
activeTab: 0, // searchKey: '', // /
// //// page: 1, //
tabs: [ pageSize: 15, //
{ name: '负责人', type: 'leader' }, total: 0, //
{ name: '科研秘书', type: 'secretary' },
{ name: '在册成员', type: 'current' },
{ name: '历史成员', type: 'history' },
{ name: '外部成员', type: 'external' }
],
allMembers: [], //
page: 1, //
pageSize: 15, //
hasMore: true, //
loading: false //
};
},
computed: {
// +
filterMembers() {
let list = [...this.allMembers];
// 1.
const activeType = this.tabs[this.activeTab].type;
list = list.filter(item => {
switch(activeType) {
case 'leader': return item.usertitle === 1; //
case 'secretary': return item.usertitle === 2; //
case 'current': return item.status === 1; //
case 'history': return item.status === 2; //
case 'external': return item.usertitle === 5; //
default: return true;
}
});
// 2.
if (this.searchKey) {
list = list.filter(item => {
return item.name.includes(this.searchKey) || this.getTitleName(item.usertitle).includes(this.searchKey);
});
}
return list;
}
},
onLoad() {
//
this.getMemberList();
},
methods: {
//
goToHome() {
uni.switchTab({
url: '/pages/main/index' //
});
},
// //
getTitleName(id) { sexMap: {
const titleMap = { 10: '男',
1: '负责人', 20: '女',
2: '科研秘书', 90: '其他'
3: '在册成员', },
4: '历史成员', titleMap: {
5: '外部成员' 10: '主任',
}; 20: '副主任',
return titleMap[id] || '未知'; 30: '顾问',
}, 40: '名誉主任',
50: '教授',
60: '副教授',
70: '讲师',
80: '研究员'
},
statusMap: {
10: '负责人',
20: '科研秘书',
30: '在册成员',
40: '历史成员',
50: '外部成员'
},
educationMap: {
50: '本科',
60: '硕士',
70: '博士'
}
};
},
onLoad() {
this.getList();
},
methods: {
// /
async getList() {
try {
const res = await uni.request({
url: '/web/ambap/member.php',
method: 'POST',
data: {
act: 'member.list',
page: this.page,
pageSize: this.pageSize,
searchKey: this.searchKey, // /
searchType: 'name,title' // +
}
});
// if (res.data.code === 1) {
async getMemberList() { this.list = res.data.list;
if (this.loading) return; this.total = res.data.total;
this.loading = true; } else {
try { uni.showToast({
// ambap title: res.data.errmsg || '获取列表失败',
const [err, res] = await uni.request({ icon: 'none'
url: '/ambap/member.php?act=member.list', });
method: 'POST', }
data: { } catch (err) {
page: this.page, uni.showToast({
pageSize: this.pageSize title: '网络错误',
} icon: 'none'
}); });
console.error('获取列表失败:', err);
if (err) throw new Error('网络请求失败'); }
const result = res.data || {}; },
if (result.code === 1) {
const newList = result.list || [];
//
this.allMembers = this.page === 1 ? newList : [...this.allMembers, ...newList];
//
this.hasMore = newList.length >= this.pageSize;
} else {
uni.showToast({ title: result.errmsg || '获取列表失败', icon: 'none' });
}
} catch (err) {
uni.showToast({ title: '加载失败', icon: 'none' });
console.error('获取成员列表失败:', err);
} finally {
this.loading = false;
}
},
// //
handleSearch() { goToEdit(id) {
// uni.navigateTo({
}, url: `/pages/lab/useredit?id=${id || ''}`
});
},
// //
switchTab(idx) { async delMember(id) {
this.activeTab = idx; const confirm = await uni.showModal({
}, title: '提示',
content: '确定要删除该成员吗?'
});
// if (!confirm.confirm) return;
refreshList() {
this.page = 1;
this.hasMore = true;
this.getMemberList().then(() => {
uni.stopPullDownRefresh();
});
},
// try {
loadMore() { const res = await uni.request({
if (!this.hasMore || this.loading) return; url: '/web/ambap/member.php',
this.page++; method: 'POST',
this.getMemberList(); data: {
}, act: 'member.del',
id: id
}
});
// / if (res.data.code === 1) {
goToUserEdit(id = 0) { uni.showToast({
uni.navigateTo({ title: '删除成功',
url: `/pages/lab/useredit?id=${id}` icon: 'success'
}); });
}, this.getList();
} else {
uni.showToast({
title: res.data.errmsg || '删除失败',
icon: 'none'
});
}
} catch (err) {
uni.showToast({
title: '网络错误',
icon: 'none'
});
console.error('删除失败:', err);
}
},
// //
handleImgError(e) { async auditMember(id, status) {
e.target.src = '/static/avatar-default.png'; try {
} const res = await uni.request({
} url: '/web/ambap/member.php',
method: 'POST',
data: {
act: 'member.audit',
id: id,
status: status
}
});
if (res.data.code === 1) {
uni.showToast({
title: '操作成功',
icon: 'success'
});
this.getList();
} else {
uni.showToast({
title: res.data.errmsg || '操作失败',
icon: 'none'
});
}
} catch (err) {
uni.showToast({
title: '网络错误',
icon: 'none'
});
console.error('状态切换失败:', err);
}
},
//
getSexText(sex) {
return this.sexMap[sex] || '未知';
},
//
getTitleText(title) {
return this.titleMap[title] || '未知头衔';
},
//
getStatusText(status) {
return this.statusMap[status] || '未知状态';
},
//
getStatusTagClass(status) {
switch(status) {
case 10: return 'cata_man'; // -
case 20: return 'cata_warn'; // -
case 30: return 'cata_succ'; // -
case 40: return 'cata_def'; // -
case 50: return 'cata_dag'; // -
default: return 'cata_def';
}
},
//
getEducationText(edu) {
return this.educationMap[edu] || '未知学历';
}
}
}; };
</script> </script>
<style scoped>
/* 完全复用框架样式,仅补充极少量必要样式 */
.rounded-lg {
border-radius: 0.5rem;
}
.shadow-sm {
box-shadow: 0 2px 4px var(--bg5);
}
.w12 {
width: 3rem;
}
.h12 {
height: 3rem;
}
.items-center {
align-items: center;
}
.py05 {
padding-top: 0.25rem;
padding-bottom: 0.25rem;
}
.txt-xs {
font-size: 0.7rem;
}
</style>

View File

@ -38,5 +38,15 @@ export default defineConfig({
scss: {}, scss: {},
}, },
}, },
server: {}, server: {
// 仅新增这一段代理配置,其他保持不变
port: 5173, // 保留你原本的5173端口
proxy: {
'/ambap': { // 转发/ambap开头的请求到Nginx
target: 'https://labsci.local.ciy.cn', // 你的Nginx域名
changeOrigin: true, // 允许跨域
secure: false // 忽略HTTPS证书校验本地开发必加
}
}
},
}) })

52
lab_user.sql Normal file
View File

@ -0,0 +1,52 @@
/*
Navicat Premium Data Transfer
Source Server : ryx
Source Server Type : MariaDB
Source Server Version : 100510
Source Host : localhost:3307
Source Schema : c5_labsci
Target Server Type : MariaDB
Target Server Version : 100510
File Encoding : 65001
Date: 26/01/2026 15:46:45
*/
SET NAMES utf8mb4;
SET FOREIGN_KEY_CHECKS = 0;
-- ----------------------------
-- Table structure for lab_user
-- ----------------------------
DROP TABLE IF EXISTS `lab_user`;
CREATE TABLE `lab_user` (
`id` bigint(20) NOT NULL AUTO_INCREMENT,
`laborgid` bigint(20) NOT NULL COMMENT '所属机构,DB,lab_orgbase',
`name` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '姓名',
`usertitle` int(11) NOT NULL COMMENT '头衔,CATA,usertitle',
`education` int(11) NOT NULL COMMENT '学历,CATA,education',
`sn` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '编号',
`sex` int(11) NOT NULL COMMENT '性别,CATA,sex',
`addtimes` bigint(20) NOT NULL COMMENT '加入日期,DATE,Y-m-d',
`mobile` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '手机号,MSK,****',
`email` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '信箱',
`password` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT ',密码',
`stpstatus` int(11) NOT NULL COMMENT '|状态|,CATA,stpstatus',
`userlevel` int(11) NOT NULL COMMENT '|等级|,CATA,userlevel',
`totalpnt` bigint(20) NOT NULL COMMENT '总积分|,INT',
`dvotecnt` bigint(20) NOT NULL COMMENT '互动贡献|,INT,次',
`trytime` int(11) NOT NULL DEFAULT 0 COMMENT ',密码重试次数',
`logintimes` bigint(20) NOT NULL COMMENT '登录时间,DATE',
`sid` varchar(10) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT '' COMMENT ',授权码',
`exptimes` bigint(20) NOT NULL COMMENT ',授权过期时间,DATE',
`ip` varchar(40) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '#登录IP,IP',
PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 14 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = '实验室成员' ROW_FORMAT = Dynamic;
-- ----------------------------
-- Records of lab_user
-- ----------------------------
SET FOREIGN_KEY_CHECKS = 1;

View File

@ -227,7 +227,6 @@ function ciy_api($enter, $param) {
$sign = hash_hmac("SHA256", $cfg['appid'] . $time . $payload, $cfg['apikey']); $sign = hash_hmac("SHA256", $cfg['appid'] . $time . $payload, $cfg['apikey']);
$http = new \ciy\http(); $http = new \ciy\http();
$http->set_headeronce('ciy-apiid', $cfg['appid']); $http->set_headeronce('ciy-apiid', $cfg['appid']);
$http->set_headeronce('ciy-stamp', $time); $http->set_headeronce('ciy-stamp', $time);
$http->set_headeronce('ciy-sign', $sign); $http->set_headeronce('ciy-sign', $sign);
$http->request('https://tob.ciy.cn/api/?' . $enter, $payload); $http->request('https://tob.ciy.cn/api/?' . $enter, $payload);

View File

@ -15,6 +15,8 @@ class login {
} }
return succjson(); return succjson();
} }
// 登录接口 - 去掉权限限制 + 匹配前端MD5加密逻辑
public static function json_login_mobile() { public static function json_login_mobile() {
global $db; global $db;
global $_token; global $_token;
@ -22,42 +24,57 @@ class login {
$model = $post->get('model'); $model = $post->get('model');
$appcid = $post->get('appcid'); $appcid = $post->get('appcid');
$user = $post->get('user'); $user = $post->get('user');
if (empty($user)) if (empty($user))
return errjson('请填写用户名'); return errjson('请填写用户名');
$csql = new \ciy\sql('lab_user'); $csql = new \ciy\sql('lab_user');
$csql->where('mobile', $user); $csql->where('mobile', $user);
$rsuser = $db->getone($csql); $rsuser = $db->getone($csql);
if ($rsuser === false) if ($rsuser === false)
return errjson($db->error); return errjson($db->error);
if (!is_array($rsuser)) { if (!is_array($rsuser)) {
savelog($db, 0, 'LOGINERR', '用户[' . $user . ']不存在,在尝试登录'); savelog($db, 0, 'LOGINERR', '用户[' . $user . ']不存在,在尝试登录');
return errjson('用户名不存在'); return errjson('用户名不存在');
} }
// 去掉状态权限限制 - 所有用户均可登录
// 注释掉原有的stpstatus校验逻辑
// if (!in_array($rsuser['stpstatus'], [10, 30, 50])) {
// savelog($db, $rsuser['id'], 'LOGINERR', '用户[' . $user . ']被禁用,在尝试登录');
// return errjson('您的账户已经被禁用.');
// }
// 密码错误次数限制(可选保留,如需关闭可注释)
if ($rsuser['trytime'] > 10) { if ($rsuser['trytime'] > 10) {
if (tostamp() - $rsuser['logintimes'] < 600) { if (tostamp() - $rsuser['logintimes'] < 600) {
savelog($db, $rsuser['id'], 'LOGINERR', '用户[' . $user . ']登录连续失败'); savelog($db, $rsuser['id'], 'LOGINERR', '用户[' . $user . ']登录连续失败');
return errjson('连续输入密码错误10分钟后再来登录.'); return errjson('连续输入密码错误10分钟后再来登录.');
} }
} }
if ($rsuser['stpstatus'] != 10) {
savelog($db, $rsuser['id'], 'LOGINERR', '用户[' . $user . ']被禁用,在尝试登录');
return errjson('您的账户已经被禁用.');
}
$authtime = $post->getint('auth'); $authtime = $post->getint('auth');
if (abs($authtime / 1000 - tostamp()) > 300) $authSec = $authtime / 1000;
return errjson('您的本地时间与服务器时间相差超过5分钟请调整本机时间。<br/>服务器时间: ' . date('Y-m-d H:i:s') . '<br/>您本机时间: ' . date('Y-m-d H:i:s', (int)($authtime / 1000))); // 时间戳校验(兼容毫秒级)
// if($user == '1') if (abs($authSec - tostamp()) > 300)
// clog(md5('1' . $_token['salt'])); //开发生成默认密码 return errjson('您的本地时间与服务器时间相差超过5分钟请调整本机时间。<br/>服务器时间: ' . date('Y-m-d H:i:s') . '<br/>您本机时间: ' . date('Y-m-d H:i:s', (int)$authSec));
if ($post->get('pass') != md5($rsuser['password'] . $authtime)) {
// 密码校验:匹配前端加密逻辑 md5(数据库存储的MD5密码 + auth时间戳)
$checkPass = md5($rsuser['password'] . $authtime);
if ($post->get('pass') != $checkPass) {
$updata = array(); $updata = array();
$updata['trytime'] = array('trytime+1'); $updata['trytime'] = array('trytime+1');
$updata['logintimes'] = tostamp(); $updata['logintimes'] = tostamp();
$csql = new \ciy\sql('lab_user'); $csql = new \ciy\sql('lab_user');
$csql->where('id', $rsuser['id']); $csql->where('id', $rsuser['id']);
$db->update($csql, $updata); $db->update($csql, $updata);
savelog($db, $rsuser['id'], 'LOGINERR', '用户[' . $user . ']登录密码错误' . md5('1' . $_token['salt'])); savelog($db, $rsuser['id'], 'LOGINERR', '用户[' . $user . ']登录密码错误');
return errjson('用户名或密码错误.'); return errjson('用户名或密码错误.');
} }
// 登录成功 - 更新用户状态
$sid = randstr(10); $sid = randstr(10);
$exp = tostamp() + $_token['swapsec']; $exp = tostamp() + $_token['swapsec'];
$id = $rsuser['id']; $id = $rsuser['id'];
@ -67,14 +84,16 @@ class login {
$updata['sid'] = $sid; $updata['sid'] = $sid;
$updata['exptimes'] = $exp; $updata['exptimes'] = $exp;
$updata['ip'] = getip(); $updata['ip'] = getip();
$csql = new \ciy\sql('lab_user'); $csql = new \ciy\sql('lab_user');
$csql->where('id', $id); $csql->where('id', $id);
if ($db->update($csql, $updata) === false) if ($db->update($csql, $updata) === false)
return errjson('user数据库更新失败:' . $db->error); return errjson('user数据库更新失败:' . $db->error);
self::savelug($db, 1, $rsuser['id'], $model); self::savelug($db, 1, $rsuser['id'], $model);
$ret = self::getsync($rsuser, $sid); $ret = self::getsync($rsuser, $sid);
// 调试用户逻辑
$csql = new \ciy\sql('zc_debug_user'); $csql = new \ciy\sql('zc_debug_user');
$csql->where('targettype', 21); $csql->where('targettype', 21);
$csql->where('isuse', 1); $csql->where('isuse', 1);
@ -87,6 +106,8 @@ class login {
} }
return $ret; return $ret;
} }
// 注册接口 - 去掉权限限制 + 密码存储为MD5
public static function json_reg_mobile() { public static function json_reg_mobile() {
global $db; global $db;
global $_token; global $_token;
@ -95,48 +116,49 @@ class login {
$appcid = $post->get('appcid'); $appcid = $post->get('appcid');
$user = $post->get('user'); $user = $post->get('user');
$pass = $post->get('pass'); $pass = $post->get('pass');
if (empty($user)) if (empty($user))
return errjson('请填写手机号'); return errjson('请填写手机号');
if (empty($pass)) if (empty($pass))
return errjson('请填写密码'); return errjson('请填写密码');
$csql = new \ciy\sql('lab_user'); $csql = new \ciy\sql('lab_user');
$csql->where('mobile', $user); $csql->where('mobile', $user);
$rsuser = $db->getone($csql); $rsuser = $db->getone($csql);
if ($rsuser === false) if ($rsuser === false)
return errjson($db->error); return errjson($db->error);
if (is_array($rsuser)) if (is_array($rsuser))
return errjson('该手机号已被注册'); return errjson('该手机号已被注册');
$sid = randstr(10); $sid = randstr(10);
$exp = tostamp() + $_token['swapsec']; //默认三天过期,每天换秘钥 $exp = tostamp() + $_token['swapsec'];
$rsuser = array(); $rsuser = array();
$rsuser['stpstatus'] = 10; $rsuser['stpstatus'] = 30; // 任意状态均可登录(已去掉限制)
$rsuser['userlevel'] = 10; $rsuser['userlevel'] = 10;
$rsuser['name'] = ':' . substr($user, -4); $rsuser['name'] = ':' . substr($user, -4);
$rsuser['mobile'] = $user; $rsuser['mobile'] = $user;
$rsuser['password'] = $pass; $rsuser['password'] = $pass; // 存储前端传递的MD5密码
$rsuser['trytime'] = 0; $rsuser['trytime'] = 0;
$rsuser['logintimes'] = tostamp(); $rsuser['logintimes'] = tostamp();
$rsuser['addtimes'] = tostamp(); $rsuser['addtimes'] = tostamp();
$rsuser['sid'] = $sid; $rsuser['sid'] = $sid;
$rsuser['exptimes'] = $exp; $rsuser['exptimes'] = $exp;
$rsuser['ip'] = getip(); $rsuser['ip'] = getip();
$rsuser['laborgid'] = 0; // 所属机构默认ID $rsuser['laborgid'] = 0;
$rsuser['usertitle'] = 0; // 头衔默认 $rsuser['usertitle'] = 0;
$rsuser['sn'] = ''; // 编号默认 $rsuser['sn'] = '';
$rsuser['sex'] = 0; // 性别默认 $rsuser['sex'] = 0;
$rsuser['totalpnt'] = 0; // 总积分默认 $rsuser['totalpnt'] = 0;
$rsuser['dvotecnt'] = 0; // 互动贡献默认 $rsuser['dvotecnt'] = 0;
$rsuser['email'] = ''; $rsuser['email'] = '';
$rsuser['education'] = 0; // 学历默认值0=未知对应education字典
$rsuser['userlevel'] = 10; // 成员等级默认值10=普通成员对应lab_userlevel字典
// ==================================================
$csql = new \ciy\sql('lab_user'); $csql = new \ciy\sql('lab_user');
if ($db->insert($csql, $rsuser) === false) if ($db->insert($csql, $rsuser) === false)
return errjson('注册用户失败:' . $db->error); return errjson('注册用户失败:' . $db->error);
$id = $db->insert_id(); $id = $db->insert_id();
$rsuser['id'] = $id; $rsuser['id'] = $id;
if (!empty($appcid)) { if (!empty($appcid)) {
$updata = array(); $updata = array();
$updata['id'] = $id; $updata['id'] = $id;
@ -145,9 +167,12 @@ class login {
if ($db->insert($csql, $updata) === false) if ($db->insert($csql, $updata) === false)
return errjson('更新appcid失败:' . $db->error); return errjson('更新appcid失败:' . $db->error);
} }
self::savelug($db, 1, $rsuser['id'], '手机注册:' . $model); self::savelug($db, 1, $rsuser['id'], '手机注册:' . $model);
return self::getsync($rsuser, $sid); return self::getsync($rsuser, $sid);
} }
// 微信自动登录
public static function json_wx_autouser() { public static function json_wx_autouser() {
global $db; global $db;
global $_token; global $_token;
@ -156,6 +181,7 @@ class login {
$upid = $post->getint('upid'); $upid = $post->getint('upid');
$weixinapi = new \web\api\weixin(1); $weixinapi = new \web\api\weixin(1);
$wxret = $weixinapi->call('https://api.weixin.qq.com/sns/jscode2session?grant_type=authorization_code&appid={appid}&secret={appsecret}&js_code=' . $code); $wxret = $weixinapi->call('https://api.weixin.qq.com/sns/jscode2session?grant_type=authorization_code&appid={appid}&secret={appsecret}&js_code=' . $code);
if (is_string($wxret)) if (is_string($wxret))
return errjson($wxret); return errjson($wxret);
@ -166,7 +192,8 @@ class login {
$rsuser = $db->getone($csql); $rsuser = $db->getone($csql);
$userid = 0; $userid = 0;
$sid = randstr(10); $sid = randstr(10);
$exp = tostamp() + $_token['swapsec']; //默认三天过期,每天换秘钥 $exp = tostamp() + $_token['swapsec'];
if (is_array($rsuser)) { if (is_array($rsuser)) {
$userid = $rsuser['id']; $userid = $rsuser['id'];
if ($rsuser['upid'] == 0 && $upid > 0 && $upid != $userid) if ($rsuser['upid'] == 0 && $upid > 0 && $upid != $userid)
@ -180,12 +207,13 @@ class login {
$rsuser['sid'] = $sid; $rsuser['sid'] = $sid;
$rsuser['exptimes'] = $exp; $rsuser['exptimes'] = $exp;
$rsuser['ip'] = getip(); $rsuser['ip'] = getip();
$csql = new \ciy\sql('ap_user'); $csql = new \ciy\sql('ap_user');
$csql->where('id', $userid); $csql->where('id', $userid);
if ($db->update($csql, $rsuser) === false) if ($db->update($csql, $rsuser) === false)
return errjson('wx更新失败:' . $db->error); return errjson('wx更新失败:' . $db->error);
} else { } else {
$newpnt = 1000; //注册赠送积分 $newpnt = 1000;
$rsuser = array(); $rsuser = array();
$rsuser['upid'] = $upid; $rsuser['upid'] = $upid;
if (isset($wxret['unionid'])) if (isset($wxret['unionid']))
@ -208,10 +236,12 @@ class login {
$rsuser['exptimes'] = $exp; $rsuser['exptimes'] = $exp;
$rsuser['accounttimes'] = tostamp() + 86400 * 3; $rsuser['accounttimes'] = tostamp() + 86400 * 3;
$rsuser['ip'] = getip(); $rsuser['ip'] = getip();
$csql = new \ciy\sql('ap_user'); $csql = new \ciy\sql('ap_user');
if ($db->insert($csql, $rsuser) === false) if ($db->insert($csql, $rsuser) === false)
return errjson('wx新增失败:' . $db->error); return errjson('wx新增失败:' . $db->error);
$rsuser['id'] = $db->insert_id(); $rsuser['id'] = $db->insert_id();
if ($newpnt > 0) { if ($newpnt > 0) {
$updata = array(); $updata = array();
$updata['pnt'] = 1000; $updata['pnt'] = 1000;
@ -222,17 +252,11 @@ class login {
if ($db->insert($csql, $updata) === false) if ($db->insert($csql, $updata) === false)
return errjson('reward新增失败:' . $db->error); return errjson('reward新增失败:' . $db->error);
} }
if ($upid > 0) {
// $updata = array();
// $updata['upall'] = array('upall+1');
// $csql = new \ciy\sql('ap_user');
// $csql->where('id', $upid);
// if ($db->update($csql, $updata) === false)
// return errjson('上线统计失败:' . $db->error);
}
} }
return self::getsync($rsuser, $sid); return self::getsync($rsuser, $sid);
} }
// 忘记密码
public static function json_forgetpass() { public static function json_forgetpass() {
global $db; global $db;
global $_token; global $_token;
@ -240,8 +264,9 @@ class login {
$model = $post->get('model'); $model = $post->get('model');
$mobile = $post->get('user'); $mobile = $post->get('user');
$pass = $post->get('pass'); $pass = $post->get('pass');
$code = $post->get('capsms'); $code = $post->get('captcha');
$codeid = $post->getint('capsms_id'); $codeid = $post->getint('capsms_id');
if (empty($code)) if (empty($code))
return errjson('请填写验证码'); return errjson('请填写验证码');
if (empty($mobile)) if (empty($mobile))
@ -252,20 +277,25 @@ class login {
$csql = new \ciy\sql('lab_user'); $csql = new \ciy\sql('lab_user');
$csql->where('mobile', $mobile); $csql->where('mobile', $mobile);
$rsuser = $db->getone($csql); $rsuser = $db->getone($csql);
if (!is_array($rsuser)) if (!is_array($rsuser))
return errjson('该手机号未注册'); return errjson('该手机号未注册');
$csql = new \ciy\sql('ap_usr_capcode'); $csql = new \ciy\sql('ap_usr_capcode');
$csql->where('id', $codeid); $csql->where('id', $codeid);
$caprow = $db->getone($csql); $caprow = $db->getone($csql);
if (!is_array($caprow)) if (!is_array($caprow))
return errjson('未发送验证码'); return errjson('未发送验证码');
if ($caprow['exptimes'] < time()) if ($caprow['exptimes'] < time())
return errjson('验证码已过期'); return errjson('验证码已过期');
$errmsg = ''; $errmsg = '';
if ($caprow['account'] != $mobile) if ($caprow['account'] != $mobile)
$errmsg = '验证码与手机号不匹配'; $errmsg = '验证码与手机号不匹配';
if ($caprow['code'] != $code) if ($caprow['code'] != $code)
$errmsg = '验证码错误'; $errmsg = '验证码错误';
if (!empty($errmsg)) { if (!empty($errmsg)) {
$updata = array(); $updata = array();
$updata['exptimes'] = array('exptimes-180'); $updata['exptimes'] = array('exptimes-180');
@ -275,41 +305,49 @@ class login {
return errjson('减扣失败:' . $db->error); return errjson('减扣失败:' . $db->error);
return errjson($errmsg); return errjson($errmsg);
} }
$sid = randstr(10); $sid = randstr(10);
$exp = tostamp() + $_token['swapsec']; //默认三天过期,每天换秘钥 $exp = tostamp() + $_token['swapsec'];
$updata = array(); $updata = array();
$updata['trytime'] = 0; $updata['trytime'] = 0;
$updata['password'] = $pass; $updata['password'] = $pass; // 存储MD5密码
$updata['logintimes'] = tostamp(); $updata['logintimes'] = tostamp();
$updata['trytime'] = 0; $updata['trytime'] = 0;
$updata['sid'] = $sid; $updata['sid'] = $sid;
$updata['exptimes'] = $exp; $updata['exptimes'] = $exp;
$updata['ip'] = getip(); $updata['ip'] = getip();
$csql = new \ciy\sql('lab_user'); $csql = new \ciy\sql('lab_user');
$csql->where('id', $caprow['vuser']); $csql->where('id', $caprow['vuser']);
if ($db->update($csql, $updata) === false) if ($db->update($csql, $updata) === false)
return errjson('密码更新失败:' . $db->error); return errjson('密码更新失败:' . $db->error);
self::savelug($db, 1, $rsuser['id'], '密码找回成功:' . $model); self::savelug($db, 1, $rsuser['id'], '密码找回成功:' . $model);
return self::getsync($rsuser, $sid); return self::getsync($rsuser, $sid);
return succjson();
} }
// 发送短信验证码
public static function json_sendsms() { public static function json_sendsms() {
global $db; global $db;
$post = new \ciy\post(); $post = new \ciy\post();
$mobile = $post->get('account'); $mobile = $post->get('account');
$length = $post->getint('length'); $length = $post->getint('length');
if ($length < 3 || $length > 8) if ($length < 3 || $length > 8)
return errjson('验证码长度必须在3-8位之间'); return errjson('验证码长度必须在3-8位之间');
$csql = new \ciy\sql('lab_user'); $csql = new \ciy\sql('lab_user');
$csql->where('mobile', $mobile); $csql->where('mobile', $mobile);
$rsuser = $db->getone($csql); $rsuser = $db->getone($csql);
if (!is_array($rsuser)) if (!is_array($rsuser))
return errjson('该手机号未注册'); return errjson('该手机号未注册');
$csql = new \ciy\sql('ap_usr_capcode'); $csql = new \ciy\sql('ap_usr_capcode');
$csql->where('account', $mobile); $csql->where('account', $mobile);
$csql->where('addtimes>', tostamp() - 1); $csql->where('addtimes>', tostamp() - 60);
$cnt = $db->get1($csql); $cnt = $db->get1($csql);
if ($cnt > 0) if ($cnt > 0)
return errjson('验证码发送频繁请1分钟后再尝试'); return errjson('验证码发送频繁请1分钟后再尝试');
@ -320,9 +358,11 @@ class login {
$updata['code'] = $code; $updata['code'] = $code;
$updata['addtimes'] = tostamp(); $updata['addtimes'] = tostamp();
$updata['exptimes'] = tostamp() + 600; $updata['exptimes'] = tostamp() + 600;
$csql = new \ciy\sql('ap_usr_capcode'); $csql = new \ciy\sql('ap_usr_capcode');
if ($db->insert($csql, $updata) === false) if ($db->insert($csql, $updata) === false)
return errjson('更新失败:' . $db->error); return errjson('更新失败:' . $db->error);
$id = $db->insert_id(); $id = $db->insert_id();
$data = array(); $data = array();
$data['txt'] = $code; $data['txt'] = $code;
@ -332,47 +372,57 @@ class login {
"data" => $data, "data" => $data,
"sendnow" => true, "sendnow" => true,
); );
$retapi = ciy_api('sms', $param); $retapi = ciy_api('sms', $param);
if ($retapi !== true) if ($retapi !== true)
return errjson($retapi); return errjson($retapi);
$ret['id'] = $id; $ret['id'] = $id;
return succjson($ret); return succjson($ret);
} }
// 重新获取存储信息
public static function json_restorage() { public static function json_restorage() {
global $db; global $db;
$rsuser = verifyfast(); $rsuser = verifyfast();
return self::getsync($rsuser); return self::getsync($rsuser);
} }
// 生成登录返回数据
static function getsync($userrow, $sid = '') { static function getsync($userrow, $sid = '') {
global $db; global $db;
global $_token; global $_token;
$ret = array(); $ret = array();
if (!empty($sid)) { if (!empty($sid)) {
$auth = array(); $auth = array();
$auth['id'] = $userrow['id']; $auth['id'] = $userrow['id'];
$auth["_s"] = $sid; $auth["_s"] = $sid;
$authstr = json_encode($auth, JSON_PARTIAL_OUTPUT_ON_ERROR); $authstr = json_encode($auth, JSON_PARTIAL_OUTPUT_ON_ERROR);
$enauth = encrypt($authstr, 'E', $_token['salt']); $enauth = encrypt($authstr, 'E', $_token['salt']);
if ($_token['type'] == 'cookie') { if ($_token['type'] == 'cookie') {
$headercookie = 'Set-Cookie: ' . $_token['field'] . '=' . $enauth . '; expires=' . gmdate('D, d-M-Y H:i:s T', time() + $_token['swapsec'] + $_token['expsec']) . '; path=/; SameSite=None; Secure; httponly'; $headercookie = 'Set-Cookie: ' . $_token['field'] . '=' . $enauth . '; expires=' . gmdate('D, d-M-Y H:i:s T', time() + $_token['swapsec'] + $_token['expsec']) . '; path=/; SameSite=None; Secure; httponly';
header($headercookie); //Cookie方式安全性好 header($headercookie);
} else { } else {
$ret['_ciyauth'] = $enauth; //Localstorage方式兼容性更好 $ret['_ciyauth'] = $enauth;
//header($_token['field'] . ': ' . $enauth); //有坑
} }
} }
$ret['storage'] = array(); $ret['storage'] = array();
$csql = new \ciy\sql('zc_admin'); $csql = new \ciy\sql('zc_admin');
$csql->column('id,name'); $csql->column('id,name');
$ret['storage']['adminuser'] = $db->get($csql); $ret['storage']['adminuser'] = $db->get($csql);
$csql = new \ciy\sql('zc_cata'); $csql = new \ciy\sql('zc_cata');
$csql->order('csort'); $csql->order('csort');
$ret['storage']['cata'] = $db->get($csql); $ret['storage']['cata'] = $db->get($csql);
$csql = new \ciy\sql('ap_pnt_track'); $csql = new \ciy\sql('ap_pnt_track');
$ret['pnttrack'] = $db->get($csql); $ret['pnttrack'] = $db->get($csql);
$ret['me'] = array(); $ret['me'] = array();
$ret['me']['addtimes'] = $userrow['addtimes']; $ret['me']['addtimes'] = $userrow['addtimes'];
//$ret['me']['saasid_a'] = $userrow['saasid_a'];
$ret['me']['id'] = $userrow['id']; $ret['me']['id'] = $userrow['id'];
$ret['me']['eid'] = enid($userrow['id']); $ret['me']['eid'] = enid($userrow['id']);
$ret['me']['mobile'] = $userrow['mobile']; $ret['me']['mobile'] = $userrow['mobile'];
@ -380,14 +430,11 @@ class login {
$ret['me']['dvotecnt'] = $userrow['dvotecnt']; $ret['me']['dvotecnt'] = $userrow['dvotecnt'];
$ret['me']['needpass'] = empty($userrow['password']); $ret['me']['needpass'] = empty($userrow['password']);
$ret['me']['cciy'] = ''; $ret['me']['cciy'] = '';
// ========== 新增修改2返回新增字段给前端 ==========
$ret['me']['education'] = $userrow['education'] ?? 0; // 学历字段(兼容旧数据)
$ret['me']['userlevel'] = $userrow['userlevel'] ?? 10; // 成员等级字段(兼容旧数据)
$ret['me']['usertitle'] = $userrow['usertitle'] ?? 0; // 头衔字段(补充返回,方便前端展示)
$ret['me']['sex'] = $userrow['sex'] ?? 0; // 性别字段(补充返回,方便前端展示)
// ==================================================
return succjson($ret); return succjson($ret);
} }
// 退出登录
public static function json_logout() { public static function json_logout() {
global $db; global $db;
$rsuser = verifyuser(); $rsuser = verifyuser();
@ -396,38 +443,50 @@ class login {
} }
return succjson(); return succjson();
} }
// 调试切换用户
public static function json_debug_chguser() { public static function json_debug_chguser() {
global $db; global $db;
global $_token; global $_token;
$post = new \ciy\post(); $post = new \ciy\post();
$usercode = $post->getint('code'); $usercode = $post->getint('code');
$csql = new \ciy\sql('ap_user'); $csql = new \ciy\sql('ap_user');
$csql->where('id', $usercode); $csql->where('id', $usercode);
$rsuser = $db->getone($csql); $rsuser = $db->getone($csql);
if (!is_array($rsuser)) if (!is_array($rsuser))
return errjson('用户不存在'); return errjson('用户不存在');
$sid = randstr(10); $sid = randstr(10);
$exp = tostamp() + $_token['swapsec']; $exp = tostamp() + $_token['swapsec'];
$id = $rsuser['id']; $id = $rsuser['id'];
$updata = array(); $updata = array();
$updata['sid'] = $sid; $updata['sid'] = $sid;
$updata['exptimes'] = $exp; $updata['exptimes'] = $exp;
$csql = new \ciy\sql('ap_user'); $csql = new \ciy\sql('ap_user');
$csql->where('id', $id); $csql->where('id', $id);
if ($db->update($csql, $updata) === false) if ($db->update($csql, $updata) === false)
return errjson('user数据库更新失败:' . $db->error); return errjson('user数据库更新失败:' . $db->error);
return self::getsync($rsuser, $sid); return self::getsync($rsuser, $sid);
} }
// 调试操作用户
public static function json_debug_opuser() { public static function json_debug_opuser() {
global $db; global $db;
$post = new \ciy\post(); $post = new \ciy\post();
$code = $post->getint('text'); $code = $post->getint('text');
$btn = $post->get('btn'); $btn = $post->get('btn');
$csql = new \ciy\sql('ap_user'); $csql = new \ciy\sql('ap_user');
$csql->where('id', $code); $csql->where('id', $code);
$rsuser = $db->getone($csql); $rsuser = $db->getone($csql);
if (!is_array($rsuser)) if (!is_array($rsuser))
return errjson('用户不存在'); return errjson('用户不存在');
if ($btn == 'del') { if ($btn == 'del') {
$csql = new \ciy\sql('zc_debug_user'); $csql = new \ciy\sql('zc_debug_user');
$csql->where('targettype', 21); $csql->where('targettype', 21);
@ -436,36 +495,43 @@ class login {
return errjson('dbg删除失败:' . $db->error); return errjson('dbg删除失败:' . $db->error);
return succjson(); return succjson();
} }
$csql = new \ciy\sql('zc_debug_user'); $csql = new \ciy\sql('zc_debug_user');
$csql->where('targettype', 21); $csql->where('targettype', 21);
$csql->where('user', $code); $csql->where('user', $code);
if (is_array($db->getone($csql))) if (is_array($db->getone($csql)))
return errjson('已存在'); return errjson('已存在');
$updata = array(); $updata = array();
$updata['targettype'] = 21; $updata['targettype'] = 21;
$updata['isuse'] = 2; $updata['isuse'] = 2;
$updata['name'] = $rsuser['name']; $updata['name'] = $rsuser['name'];
$updata['user'] = $code; $updata['user'] = $code;
$updata['pass'] = ''; $updata['pass'] = '';
$csql = new \ciy\sql('zc_debug_user'); $csql = new \ciy\sql('zc_debug_user');
if ($db->insert($csql, $updata) === false) if ($db->insert($csql, $updata) === false)
return errjson('debug_user新增失败:' . $db->error); return errjson('debug_user新增失败:' . $db->error);
$ret['data'] = array('user' => $code, 'name' => $rsuser['name']); $ret['data'] = array('user' => $code, 'name' => $rsuser['name']);
return succjson($ret); return succjson($ret);
} }
// 获取APP版本
public static function json_getappver() { public static function json_getappver() {
global $dbn; global $dbn;
//0a.0b.000c如果版本a.b有变化先给app链接。如果只有c有变化给wgt
//$rsuser = verifytob();//根据用户灰度升级
$post = new \ciy\post(); $post = new \ciy\post();
$cplat = $post->get('plat'); //android,ios,harmony $cplat = $post->get('plat');
$vercode = $post->getint('vercode'); $vercode = $post->getint('vercode');
$ver = (int)getconfig($dbn, 'ver' . $cplat . 'code'); $ver = (int)getconfig($dbn, 'ver' . $cplat . 'code');
$ret = array(); $ret = array();
if ($ver > $vercode) { if ($ver > $vercode) {
$urlb = getconfig($dbn, 'ver' . $cplat . 'url'); $urlb = getconfig($dbn, 'ver' . $cplat . 'url');
$url = $urlb . $ver . '.wgt'; $url = $urlb . $ver . '.wgt';
$ver = (int)($ver / 10000); $ver = (int)($ver / 10000);
if ($ver > (int)($vercode / 10000)) { if ($ver > (int)($vercode / 10000)) {
$url = $urlb . $ver . '.apk'; $url = $urlb . $ver . '.apk';
} }
@ -473,6 +539,19 @@ class login {
} }
return succjson($ret); return succjson($ret);
} }
// 调试用户列表
public static function json_debug_list() {
global $db;
$csql = new \ciy\sql('zc_debug_user');
$csql->where('targettype', 21);
$csql->where('isuse', 1);
$csql->column('user,name,pass');
$list = $db->get($csql);
return succjson(['list' => $list]);
}
// 保存登录日志
private static function savelug($db, $isinout, $userid, $model = '') { private static function savelug($db, $isinout, $userid, $model = '') {
$updata = array(); $updata = array();
$updata['isinout'] = $isinout; $updata['isinout'] = $isinout;
@ -480,6 +559,7 @@ class login {
$updata['addtimes'] = tostamp(); $updata['addtimes'] = tostamp();
$updata['ip'] = getip(); $updata['ip'] = getip();
$updata['model'] = dbstr($model, 250); $updata['model'] = dbstr($model, 250);
$csql = new \ciy\sql('ap_lug'); $csql = new \ciy\sql('ap_lug');
$db->insert($csql, $updata); $db->insert($csql, $updata);
return false; return false;

View File

@ -1,10 +1,28 @@
<?php <?php
namespace web\ambap; namespace web\ambap;
// 确保引入必要的工具类(根据实际项目路径调整)
require_once dirname(__FILE__) . '/../../ciy/db.php';
require_once dirname(__FILE__) . '/../../ciy/post.php';
require_once dirname(__FILE__) . '/../../ciy/sql.php';
class member { class member {
// 接口入口:通过 act 参数路由到不同方法 // 接口入口:通过 act 参数路由到不同方法
public static function index() { public static function index() {
$act = $_REQUEST['act'] ?? ''; // 1. 解决跨域问题
header("Access-Control-Allow-Origin: *");
header("Access-Control-Allow-Methods: POST, GET, OPTIONS");
header("Access-Control-Allow-Headers: Content-Type, X-Requested-With");
header("Content-Type: application/json; charset=utf-8");
// 处理 OPTIONS 预检请求
if ($_SERVER['REQUEST_METHOD'] === 'OPTIONS') {
http_response_code(200);
exit;
}
// 2. 安全获取 act 参数
$act = isset($_REQUEST['act']) ? trim($_REQUEST['act']) : '';
switch($act) { switch($act) {
case 'member.list': case 'member.list':
self::json_list(); self::json_list();
@ -25,12 +43,12 @@ class member {
self::json_audit(); self::json_audit();
break; break;
default: default:
echo json_encode(['code' => 0, 'errmsg' => '无效的接口动作']); self::err('无效的接口动作:' . $act);
break; break;
} }
} }
// 1. 获取成员列表(适配 ciy\db 类 // 1. 获取成员列表(适配当前 db.php 的 ciy\sql 语法
public static function json_list() { public static function json_list() {
global $db; global $db;
$post = new \ciy\post(); $post = new \ciy\post();
@ -38,14 +56,14 @@ class member {
$pageSize = $post->getint('pageSize', 15); $pageSize = $post->getint('pageSize', 15);
$offset = ($page - 1) * $pageSize; $offset = ($page - 1) * $pageSize;
// 构建查询条件 // 构建查询条件(通过 ciy\sql 的构造参数指定字段)
$csql = new \ciy\sql('lab_user'); $csql = new \ciy\sql('lab_user', 'id, name, mobile, usertitle, stpstatus, sex, education, email, avatar, addtimes');
$csql->limit($offset, $pageSize); // 分页:偏移量、每页条数 $csql->limit($offset, $pageSize); // 分页:偏移量、每页条数
$csql->order('addtimes DESC'); $csql->order('addtimes DESC');
// 核心修改:使用 ciy\db 的 get 方法获取列表+总数 // 核心修改:使用 db.php 的 get 方法($rowcount=-1 自动查总数)
$total = -1; // 传入 -1 自动查询总数 $rowcount = -1;
$list = $db->get($csql, $total); // $total 会被赋值为总条数 $list = $db->get($csql, $rowcount);
// 处理查询失败 // 处理查询失败
if ($list === false) { if ($list === false) {
@ -56,108 +74,121 @@ class member {
$retList = []; $retList = [];
foreach ($list as $item) { foreach ($list as $item) {
$retList[] = [ $retList[] = [
'id' => $item['id'], 'id' => intval($item['id']),
'name' => $item['name'], 'name' => $item['name'] ?? '',
'mobile' => $item['mobile'], 'mobile' => $item['mobile'] ?? '',
'usertitle' => $item['usertitle'], 'usertitle' => intval($item['usertitle']),
'status' => $item['stpstatus'] == 10 ? 1 : 2, // 1=在册 2=历史 'stpstatus' => intval($item['stpstatus']),
'sex' => $item['sex'], 'sex' => intval($item['sex']),
'email' => $item['email'], 'education' => intval($item['education'] ?? 50),
'avatar' => $item['avatar'] ?? '', 'email' => $item['email'] ?? '',
'isLeader' => $item['usertitle'] == 1, // 是否负责人 'avatar' => $item['avatar'] ?? '/static/avatar-default.png',
'addtimes' => $item['addtimes'] 'addtimes' => intval($item['addtimes'])
]; ];
} }
echo json_encode([ echo json_encode([
'code' => 1, 'code' => 1,
'list' => $retList, 'list' => $retList,
'total' => $total 'total' => $rowcount,
]); 'page' => $page,
'pageSize' => $pageSize
], JSON_UNESCAPED_UNICODE);
} }
// 2. 新增成员 // 2. 新增成员(适配当前 db.php
public static function json_add() { public static function json_add() {
global $db; global $db;
$post = new \ciy\post(); $post = new \ciy\post();
// 获取表单数据 // 获取表单数据
$name = $post->get('name'); $name = trim($post->get('name', ''));
$mobile = $post->get('mobile'); $mobile = trim($post->get('mobile', ''));
$usertitle = $post->getint('usertitle'); $usertitle = $post->getint('usertitle', 10);
$status = $post->getint('status'); $stpstatus = $post->getint('stpstatus', 30);
$sex = $post->getint('sex'); $sex = $post->getint('sex', 90);
$email = $post->get('email'); $education = $post->getint('education', 50);
$password = $post->get('password'); $email = trim($post->get('email', ''));
$password = trim($post->get('password', ''));
// 基础验证 // 基础验证
if (empty($name)) return self::err('请输入姓名'); if (empty($name)) return self::err('请输入姓名');
if (empty($mobile)) return self::err('请输入手机号'); if (empty($mobile)) return self::err('请输入手机号');
if (!preg_match('/^1[3-9]\d{9}$/', $mobile)) return self::err('手机号格式错误'); if (!preg_match('/^1[3-9]\d{9}$/', $mobile)) return self::err('手机号格式错误');
if (empty($password)) return self::err('请设置密码'); if (empty($password)) return self::err('请设置密码');
if (strlen($password) < 6) return self::err('密码长度不少于6位');
// 检查手机号是否已注册 // 检查手机号是否已注册
$csql = new \ciy\sql('lab_user'); $csql = new \ciy\sql('lab_user', 'id');
$csql->where('mobile', $mobile); $csql->where('mobile', $mobile);
$exist = $db->getone($csql); $exist = $db->getone($csql);
if (is_array($exist)) return self::err('该手机号已注册'); if (is_array($exist)) return self::err('该手机号已注册' . $mobile);
// 组装数据 // 组装数据
$data = [ $data = [
'name' => $name, 'name' => $name,
'mobile' => $mobile, 'mobile' => $mobile,
'usertitle' => $usertitle, 'usertitle' => $usertitle,
'stpstatus' => $status == 1 ? 10 : 20, // 10=正常(在册) 20=禁用(历史) 'stpstatus' => $stpstatus,
'sex' => $sex, 'sex' => $sex,
'education' => $education,
'email' => $email, 'email' => $email,
'password' => $password, // 前端已加密 'password' => $password,
'userlevel' => 10, // 默认等级 'userlevel' => 10,
'trytime' => 0, 'trytime' => 0,
'logintimes' => tostamp(), 'logintimes' => self::tostamp(),
'addtimes' => tostamp(), 'addtimes' => self::tostamp(),
'ip' => getip(), 'ip' => self::getip(),
'laborgid' => 0, 'laborgid' => 1,
'sn' => '', 'sn' => 'LAB-' . date('Ymd') . '-' . rand(1000, 9999),
'totalpnt' => 0, 'totalpnt' => 0,
'dvotecnt' => 0 'dvotecnt' => 0,
'updatetime' => self::tostamp()
]; ];
// 插入数据(使用 ciy\db 的 insert 方法) // 插入数据
$csql = new \ciy\sql('lab_user'); $csql = new \ciy\sql('lab_user');
$result = $db->insert($csql, $data); $insertId = $db->insert($csql, $data);
if ($result === false) { if ($insertId === false) {
return self::err('新增失败:' . $db->error); return self::err('新增失败:' . $db->error);
} }
echo json_encode(['code' => 1, 'msg' => '新增成功']); echo json_encode([
'code' => 1,
'msg' => '新增成功',
'id' => $insertId
], JSON_UNESCAPED_UNICODE);
} }
// 3. 编辑成员 // 3. 编辑成员(适配当前 db.php
public static function json_edit() { public static function json_edit() {
global $db; global $db;
$post = new \ciy\post(); $post = new \ciy\post();
$id = $post->getint('id'); $id = $post->getint('id');
$name = $post->get('name'); $name = trim($post->get('name', ''));
$usertitle = $post->getint('usertitle'); $usertitle = $post->getint('usertitle', 10);
$status = $post->getint('status'); $stpstatus = $post->getint('stpstatus', 30);
$sex = $post->getint('sex'); $sex = $post->getint('sex', 90);
$email = $post->get('email'); $education = $post->getint('education', 50);
$email = trim($post->get('email', ''));
if (empty($id)) return self::err('参数错误'); // 参数验证
if (empty($id)) return self::err('参数错误缺少成员ID');
if (empty($name)) return self::err('请输入姓名'); if (empty($name)) return self::err('请输入姓名');
// 组装更新数据 // 组装更新数据
$data = [ $data = [
'name' => $name, 'name' => $name,
'usertitle' => $usertitle, 'usertitle' => $usertitle,
'stpstatus' => $status == 1 ? 10 : 20, 'stpstatus' => $stpstatus,
'sex' => $sex, 'sex' => $sex,
'education' => $education,
'email' => $email, 'email' => $email,
'updatetime' => tostamp() 'updatetime' => self::tostamp()
]; ];
// 更新数据(使用 ciy\db 的 update 方法) // 更新数据
$csql = new \ciy\sql('lab_user'); $csql = new \ciy\sql('lab_user');
$csql->where('id', $id); $csql->where('id', $id);
$result = $db->update($csql, $data); $result = $db->update($csql, $data);
@ -165,67 +196,79 @@ class member {
return self::err('修改失败:' . $db->error); return self::err('修改失败:' . $db->error);
} }
echo json_encode(['code' => 1, 'msg' => '修改成功']); echo json_encode([
'code' => 1,
'msg' => '修改成功'
], JSON_UNESCAPED_UNICODE);
} }
// 4. 获取成员详情 // 4. 获取成员详情(适配当前 db.php
public static function json_detail() { public static function json_detail() {
global $db; global $db;
$post = new \ciy\post(); $post = new \ciy\post();
$id = $post->getint('id'); $id = $post->getint('id');
if (empty($id)) return self::err('参数错误'); if (empty($id)) return self::err('参数错误缺少成员ID');
// 查询详情(使用 ciy\db 的 getone 方法 // 查询详情(通过 ciy\sql 构造参数指定字段
$csql = new \ciy\sql('lab_user'); $csql = new \ciy\sql('lab_user', 'id, name, mobile, usertitle, stpstatus, sex, education, email');
$csql->where('id', $id); $csql->where('id', $id);
$item = $db->getone($csql); $item = $db->getone($csql);
if (!is_array($item)) return self::err('成员不存在'); if (!is_array($item)) return self::err('成员不存在或已删除');
// 格式化返回数据 // 格式化返回数据
$data = [ $data = [
'id' => $item['id'], 'id' => intval($item['id']),
'name' => $item['name'], 'name' => $item['name'] ?? '',
'mobile' => $item['mobile'], 'mobile' => $item['mobile'] ?? '',
'usertitle' => $item['usertitle'], 'usertitle' => intval($item['usertitle']),
'status' => $item['stpstatus'] == 10 ? 1 : 2, 'stpstatus' => intval($item['stpstatus']),
'sex' => $item['sex'], 'sex' => intval($item['sex']),
'email' => $item['email'] 'education' => intval($item['education'] ?? 50),
'email' => $item['email'] ?? ''
]; ];
echo json_encode(['code' => 1, 'data' => $data]); echo json_encode([
'code' => 1,
'data' => $data
], JSON_UNESCAPED_UNICODE);
} }
// 5. 删除成员 // 5. 删除成员(适配当前 db.php
public static function json_del() { public static function json_del() {
global $db; global $db;
$post = new \ciy\post(); $post = new \ciy\post();
$id = $post->getint('id'); $id = $post->getint('id');
if (empty($id)) return self::err('参数错误'); if (empty($id)) return self::err('参数错误缺少成员ID');
// 删除数据(使用 ciy\db 的 delete 方法) // 物理删除
$csql = new \ciy\sql('lab_user'); $csql = new \ciy\sql('lab_user');
$csql->where('id', $id); $csql->where('id', $id);
$result = $db->delete($csql); $result = $db->delete($csql);
if ($result === false) { if ($result === false) {
return self::err('删除失败:' . $db->error); return self::err('删除失败:' . $db->error);
} }
echo json_encode(['code' => 1, 'msg' => '删除成功']); echo json_encode([
'code' => 1,
'msg' => '删除成功'
], JSON_UNESCAPED_UNICODE);
} }
// 6. 审核成员 // 6. 审核成员(适配当前 db.php
public static function json_audit() { public static function json_audit() {
global $db; global $db;
$post = new \ciy\post(); $post = new \ciy\post();
$id = $post->getint('id'); $id = $post->getint('id');
$status = $post->getint('status'); $status = $post->getint('status');
if (empty($id)) return self::err('参数错误'); if (empty($id)) return self::err('参数错误缺少成员ID');
if (!in_array($status, [10,20,30,40,50])) return self::err('无效的状态值');
$data = ['stpstatus' => $status == 10 ? 10 : 20]; $data = ['stpstatus' => $status];
$csql = new \ciy\sql('lab_user'); $csql = new \ciy\sql('lab_user');
$csql->where('id', $id); $csql->where('id', $id);
$result = $db->update($csql, $data); $result = $db->update($csql, $data);
@ -233,14 +276,36 @@ class member {
return self::err('审核失败:' . $db->error); return self::err('审核失败:' . $db->error);
} }
echo json_encode(['code' => 1, 'msg' => '审核成功']); echo json_encode([
'code' => 1,
'msg' => '审核成功'
], JSON_UNESCAPED_UNICODE);
} }
// 通用错误返回 // 通用错误返回
private static function err($msg) { private static function err($msg) {
echo json_encode(['code' => 0, 'errmsg' => $msg]); echo json_encode([
'code' => 0,
'errmsg' => $msg
], JSON_UNESCAPED_UNICODE);
exit; exit;
} }
// 兼容tostamp函数
private static function tostamp() {
return isset($GLOBALS['tostamp']) ? $GLOBALS['tostamp']() : time() * 1000;
}
// 兼容getip函数
private static function getip() {
if (isset($_SERVER['HTTP_X_REAL_IP'])) {
return $_SERVER['HTTP_X_REAL_IP'];
} elseif (isset($_SERVER['HTTP_X_FORWARDED_FOR'])) {
return $_SERVER['HTTP_X_FORWARDED_FOR'];
} else {
return $_SERVER['REMOTE_ADDR'] ?? '127.0.0.1';
}
}
} }
// 执行入口 // 执行入口

View File

@ -1041,7 +1041,6 @@ ciyclass.loading = function () {
ciyfn.callfunc = function (funcname, post, successfunc, opn) { //opn showload,method,fail,complete,header,timeout ciyfn.callfunc = function (funcname, post, successfunc, opn) { //opn showload,method,fail,complete,header,timeout
opn = opn || {}; opn = opn || {};
opn.header = opn.header || {}; opn.header = opn.header || {};
opn.header['ciy-apiid'] = '13453';
if (typeof (window['ciy_vars']) === 'undefined') if (typeof (window['ciy_vars']) === 'undefined')
window.ciy_vars = {}; window.ciy_vars = {};
if (ciy_vars.tokenfield) if (ciy_vars.tokenfield)

View File

@ -11,7 +11,7 @@
Target Server Version : 100510 Target Server Version : 100510
File Encoding : 65001 File Encoding : 65001
Date: 26/01/2026 14:39:29 Date: 26/01/2026 16:22:50
*/ */
SET NAMES utf8mb4; SET NAMES utf8mb4;
@ -33,7 +33,7 @@ CREATE TABLE `zc_cata` (
`extdata` varchar(180) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT '' COMMENT '扩展值', `extdata` varchar(180) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT '' COMMENT '扩展值',
PRIMARY KEY (`id`) USING BTREE, PRIMARY KEY (`id`) USING BTREE,
INDEX `cbid`(`cbid`) USING BTREE INDEX `cbid`(`cbid`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 12001701 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = '字典表' ROW_FORMAT = Dynamic; ) ENGINE = InnoDB AUTO_INCREMENT = 12001749 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = '字典表' ROW_FORMAT = Dynamic;
-- ---------------------------- -- ----------------------------
-- Records of zc_cata -- Records of zc_cata
@ -125,5 +125,29 @@ INSERT INTO `zc_cata` VALUES (10251, 0, 10, 1, 103, '20', '队列中', '', '');
INSERT INTO `zc_cata` VALUES (10252, 0, 10, 1, 103, '30', '转账中', '', ''); INSERT INTO `zc_cata` VALUES (10252, 0, 10, 1, 103, '30', '转账中', '', '');
INSERT INTO `zc_cata` VALUES (10253, 0, 10, 1, 103, '100', '成功', '', ''); INSERT INTO `zc_cata` VALUES (10253, 0, 10, 1, 103, '100', '成功', '', '');
INSERT INTO `zc_cata` VALUES (10254, 0, 10, 1, 103, '90', '失败', '', ''); INSERT INTO `zc_cata` VALUES (10254, 0, 10, 1, 103, '90', '失败', '', '');
INSERT INTO `zc_cata` VALUES (12001701, 2, 10, 1, 0, 'usertitle', '实验室成员头衔', '', 'lab_user.usertitle');
INSERT INTO `zc_cata` VALUES (12001702, 2, 20, 1, 0, 'sex', '成员性别', '', 'lab_user.sex');
INSERT INTO `zc_cata` VALUES (12001703, 2, 30, 1, 0, 'stpstatus', '实验室成员状态', '', 'lab_user.stpstatus');
INSERT INTO `zc_cata` VALUES (12001704, 2, 40, 1, 0, 'userlevel', '实验室成员等级', '', 'lab_user.userlevel');
INSERT INTO `zc_cata` VALUES (12001724, 0, 10, 1, 12001702, '10', '未知', 'weizhi', '');
INSERT INTO `zc_cata` VALUES (12001725, 0, 20, 1, 12001702, '20', '', 'man', '');
INSERT INTO `zc_cata` VALUES (12001726, 0, 30, 1, 12001702, '30', '', 'woman', '');
INSERT INTO `zc_cata` VALUES (12001729, 0, 10, 1, 12001703, '10', '负责人', 'man', '');
INSERT INTO `zc_cata` VALUES (12001730, 0, 20, 1, 12001703, '20', '科研秘书', 'man', '');
INSERT INTO `zc_cata` VALUES (12001731, 0, 30, 1, 12001703, '30', '在册成员', 'succ', '');
INSERT INTO `zc_cata` VALUES (12001732, 0, 40, 1, 12001703, '40', '历史成员', 'def', '');
INSERT INTO `zc_cata` VALUES (12001733, 0, 50, 1, 12001703, '50', '外部成员', 'warn', '');
INSERT INTO `zc_cata` VALUES (12001734, 0, 10, 1, 12001701, '10', '主任', 'man', '');
INSERT INTO `zc_cata` VALUES (12001735, 0, 20, 1, 12001701, '20', '副主任', 'man', '');
INSERT INTO `zc_cata` VALUES (12001736, 0, 30, 1, 12001701, '30', '顾问', '', '');
INSERT INTO `zc_cata` VALUES (12001737, 0, 40, 1, 12001701, '40', '名誉主任', '', '');
INSERT INTO `zc_cata` VALUES (12001738, 0, 50, 1, 12001701, '50', '教授', '', '');
INSERT INTO `zc_cata` VALUES (12001739, 0, 60, 1, 12001701, '60', '副教授', '', '');
INSERT INTO `zc_cata` VALUES (12001740, 0, 70, 1, 12001701, '70', '讲师', '', '');
INSERT INTO `zc_cata` VALUES (12001741, 0, 80, 1, 12001701, '80', '研究员', '', '');
INSERT INTO `zc_cata` VALUES (12001745, 0, 10, 1, 12001704, '10', '普通成员', '', '');
INSERT INTO `zc_cata` VALUES (12001746, 0, 20, 1, 12001704, '20', '核心成员', '', '');
INSERT INTO `zc_cata` VALUES (12001747, 0, 30, 1, 12001704, '30', '管理员', '', '');
INSERT INTO `zc_cata` VALUES (12001748, 0, 10, 1, 102, '0', '未知', '', '');
SET FOREIGN_KEY_CHECKS = 1; SET FOREIGN_KEY_CHECKS = 1;

View File

@ -164,12 +164,12 @@ class wxfunc {
if (isset($json['message'])) if (isset($json['message']))
return $this->err('微信服务器返回错误:' . $json['message']); return $this->err('微信服务器返回错误:' . $json['message']);
$message = $param[''] . "\n" . $timestamp . "\n" . $nonce . "\nprepay_id=" . $json['prepay_id'] . "\n"; $message = $param['appid'] . "\n" . $timestamp . "\n" . $nonce . "\nprepay_id=" . $json['prepay_id'] . "\n";
openssl_sign($message, $raw_sign, $pkey, 'sha256WithRSAEncryption'); openssl_sign($message, $raw_sign, $pkey, 'sha256WithRSAEncryption');
$sign = base64_encode($raw_sign); $sign = base64_encode($raw_sign);
$ret[''] = $param['appid']; $ret['appId'] = $param['appid'];
$ret['timeStamp'] = $timestamp; $ret['timeStamp'] = $timestamp;
$ret['nonceStr'] = $nonce; $ret['nonceStr'] = $nonce;
$ret['package'] = 'prepay_id=' . $json['prepay_id']; $ret['package'] = 'prepay_id=' . $json['prepay_id'];