实现新增

This commit is contained in:
ryx 2026-01-30 02:43:16 +08:00
parent aad8d2e96e
commit f38cd2871c
8 changed files with 559 additions and 469 deletions

View File

@ -419,6 +419,9 @@
},
{
"path":"useradd"
},
{
"path":"list"
}
]
}

View File

@ -0,0 +1,331 @@
<template>
<ciy-header title="搜索/列表/删除页" ref="header"></ciy-header>
<view v-if="init.code != 1">
<view class="px4 py4">
<view style="height:2em;width:60%;" class="ciy-skeleton"></view>
<view style="height:1em;width:40%;margin-left:1em;" class="ciy-skeleton"></view>
<view style="height:1em;width:50%;" class="ciy-skeleton"></view>
<view style="height:6em;width:100%;" class="ciy-skeleton"></view>
</view>
</view>
<view v-else>
<view class="sti" :style="{top:(header_statusbar_height+header_title_height)+'px'}">
<ciy-segment :lis="init.lis" all="全部" @change="segment_change"></ciy-segment>
<ciy-query ref="query" :gdict="g" :qry="init.searchinput" @confirm="query_confirm">
<template v-slot="{itm}">
<ciy-input :name="itm.item.form" v-model="itm.data[itm.item.form]"></ciy-input>
</template>
</ciy-query>
</view>
<view class="ciy-list" :class="{del:item._del}" v-for="(item,index) in init.list" :key="item.id" @tap="showmenu(index)">
<view class="l0">No: {{item.id}}</view>
<view v-if="item.id%2 == 0" class="rt">
<view class="code b" :class="ccode(g.auditstatus, item.auditstatus,'clas')">{{ccode(g.auditstatus, item.auditstatus)}}</view>
</view>
<view v-else class="rtz liner" :class="ccode(g.auditstatus, item.auditstatus,'clas')">
{{ccode(g.auditstatus, item.auditstatus)}}
</view>
<view class="l1 c">
<view>{{item.name}}</view>
</view>
<view class="ciy-hr"></view>
<view class="l2">审核人 {{ccode('xa_user', item.audituser)}}</view>
<view class="l2" v-if="item.auditmsg">审核理由 <text v-html="tobr(item.auditmsg)"></text></view>
<view class="l2">审核时间 {{todatetime(item.audittimes)}}</view>
<view class="ciy-hr"></view>
<view class="l2">
<label>所属菜单</label>
<view>{{ccode(init.zc_menu, item.menuid)}}</view>
</view>
<view class="l2">
<label>文件大小</label>
<view>{{tofix(item.filesize/1024, -2)}}KB</view>
</view>
<view class="l2">
<label>长度</label>
<view>{{tofix(item.metre/1000, -2)}}</view>
</view>
<view class="l2">
<label>贷款金额</label>
<view>{{tofix(item.bankmoney/1000000)}}万元</view>
</view>
<view class="l2">
<label>设置日期</label>
<view>{{todatetime(item.setdate, 'd')}}</view>
</view>
<view class="l2">
<label>设置时间</label>
<view>{{todatetime(item.settimes)}}</view>
</view>
<view class="l2">
<label>营业时间</label>
<view>{{totimepoint(item.dayclock, true)}}</view>
</view>
<ciy-showimgs label="文档" :src="item.downurl"></ciy-showimgs>
<ciy-showimgs :src="item.avar" width="20em" mode="widthFix"></ciy-showimgs>
<view class="l2">
<label>是否使用</label>
<view>{{item.isuse==1?'√':'×'}}</view>
</view>
<view class="l2">
<label>是否开启</label>
<view>{{item.isopen==1?'开启':'关闭'}}</view>
</view>
<view class="l2">
<label>库存单位</label>
<view>{{tounit(item.unit)}}</view>
</view>
<view class="l2">
<label>单选状态</label>
<view>{{ccode(g.auditstatus, item.sigstatus)}}</view>
</view>
<view class="l2">
<label>多选状态</label>
<view>
<view class="kbd" v-for="(itm, index) in scode(g.auditstatus, item.mauditstatus)" :key="index">{{itm.name}}</view>
</view>
</view>
<view class="l2">
<label>组织结构</label>
<view>{{mcode(g.zc_depart, item.prodcata, 'name').join(' . ')}}</view>
</view>
<view class="l2">
<label>所在地区</label>
<view>
<text class="code" v-for="(itm, index) in mcode(g.ciy_arearpc, item.areacode)" :key="index">{{itm.name}}</text>
</view>
</view>
<view class="l2">
<label>认证情况</label>
<view>
<text class="kbd" v-for="(itm, index) in bcode(g.renzheng, item.renzheng)" :key="index">{{itm.name}}</text>
</view>
</view>
<view class="l2">
<label>临时字典</label>
<view>{{ccode(g.ppint, item.ppint)}}</view>
</view>
<view class="l2">
<label>执行周期</label>
<view>{{tocyc(item.npcyc)}}</view>
</view>
<view class="l2">
<label>执行用时</label>
<view>{{totimesec(item.runsec)}}</view>
</view>
<view class="l2">
<label>活动期数</label>
<view>{{item.acttm}}</view>
</view>
<ciy-showimgs label="活动花絮" :src="item.imgs"></ciy-showimgs>
<view class="l2">
<label>吨位</label>
<view>{{tofix(item.ton/1000000, 3)}}</view>
</view>
<view class="l2">
<label>单价</label>
<view>{{tofix(item.price/100, 2)}}</view>
</view>
<view class="l2">
<label>位置</label>
<view><text style="text-decoration: underline;" @tap.stop="goloc(item.lat, item.lng)">查看位置</text>
</view>
</view>
<view class="l2">
<label>百分比</label>
<view>{{tofix(item.pct/100, 2)}}%</view>
</view>
<view class="l2">
<label>链接</label>
<view><text style="text-decoration: underline;" @tap.stop="goweb(item.url)">转到链接</text>
</view>
</view>
<view class="l2">
<label>体重</label>
<view>{{tofix(item.weightg/1000)}}公斤</view>
</view>
<view class="l2">
<label>耳温</label>
<view>{{tofix(item.eartmpr/1000, 1)}}</view>
</view>
<view class="l2">
<label>身份证号</label>
<view>{{tomsk(item.idcard,'******#*')}}</view>
</view>
<view class="rb">
添加时间 {{todatetime(item.addtimes)}}
</view>
</view>
<ciy-listend :page="pageno" :listlen="init.list.length" :nodataimg="file_stor('/img/mbnone.png')"></ciy-listend>
<view class="ciy-add" @tap="edit()"></view>
</view>
</template>
<style>
</style>
<script>
export default {
data() {
return {}
},
onLoad() {
this.load_ciydict(this.file_stor('/dict/ciy_arearpc.js')).then(json => {
if (json.code != 1)
return this.alert(json.errmsg);
this.g.ciy_arearpc = json.arr;
});
this.getlist();
},
onReachBottom(b) {
console.log('onReachBottom page', this.pageno);
if (this.init.code != 1)
return;
this.getlist();
},
onPullDownRefresh(b) {
console.log('onPullDownRefresh page');
this.pageno = 0;
this._stopPullDown = true;
this.getlist();
},
watch: {},
computed: {},
methods: {
async getlist() {
if (this.pageno < 0)
return;
if (this._loading)
return;
this.pagepost.pageno = this.pageno + 1;
this.pagepost.once = !this.init.once;
this._loading = true;
var retjson = await this.callfunc({
func: 'demo/demo.list',
data: this.pagepost
});
this._loading = false;
if (retjson.code != 1)
return this.alert(retjson.errmsg);
this.pageno++;
if (this.pageno == 1)
this.init.list = [];
this.init = this.objdeepmerge(this.init, retjson);
if (retjson.once) {
this.init.lis = [...this.g.auditstatus];
this.g.zc_depart = retjson.zc_depart;
this.g.ppint = retjson.ppint;
}
this.getrefs('query').then(ref => {
ref.setdata(retjson.where);
});
if (retjson.list.length < retjson.pagecount)
this.pageno = -1;
},
segment_change(e) {
this.pagepost.liid = e.value.id;
this.pageno = 0;
this.getlist();
uni.pageScrollTo({
scrollTop: 0,
duration: 800
});
},
query_confirm(dat) {
this.pagepost.query = dat;
this.pageno = 0;
this.getlist();
uni.pageScrollTo({
scrollTop: 0,
duration: 800
});
},
async edit(item) {
item = item || {
url: '',
data: {
id: 0,
_idx: -1
}
};
this.gourl('demo_edit?id=' + item.data.id, 'navigate', item.data, 'demo');
},
async del(item) {
if (await this.askmsg('是否删除?', '删除') != 'ok')
return;
var retjson = await this.callfunc({
func: 'demo/demo.del',
data: {
id: item.data.id
}
});
if (retjson.code != 1)
return this.alert(retjson.errmsg);
this.init.list[item.data._idx]._del = true;
setTimeout(() => {
this.init.list.splice(item.data._idx, 1);
}, 500);
},
async audit(item) {
var msg = await this.inputmsg({
title: '请填写审核理由',
ele: 'textarea'
}, [{
name: '审核通过',
btn: 'ok'
}, {
name: '驳回',
btn: 'ng',
cls: 'dag liner'
}, {
name: '取消',
btn: 'cancel',
cls: 'def'
}]);
if (msg.btn == 'cancel')
return;
var retjson = await this.callfunc({
func: 'demo/demo.audit',
data: {
id: item.data.id,
msg: msg.text,
status: msg.btn == 'ng' ? 90 : 100,
}
});
if (retjson.code != 1)
return this.alert(retjson.errmsg);
this.init.list[item.data._idx] = this.objdeepmerge(this.init.list[item.data._idx], retjson.data);
},
showmenu(idx) {
var dat = this.init.list[idx];
dat._idx = idx;
var items = [];
items.push({
func: 'audit',
name: '审核',
data: dat
});
items.push({
func: 'edit',
name: '变更',
data: dat
});
items.push({
func: 'del',
name: '删除',
style: 'color:var(--dag5)',
data: dat
});
this.popmenu({
items
});
}
}
}
</script>

View File

@ -1,15 +1,11 @@
<template>
<view class="ciy-page">
<!-- 页面标题 -->
<view class="ciy-title mk bg2">
<view class="title">新增实验室成员</view>
<button class="btn def sm" @click="goBack">返回</button>
</view>
<!-- 表单容器 -->
<view class="main bg4 flex1 overflow-auto px4 py3">
<form class="ciy-form-group">
<!-- 1. 姓名必填 -->
<view class="ciy-form">
<label class="imp char4">姓名</label>
<input
@ -20,64 +16,54 @@
required
/>
</view>
<!-- 2. 头像上传 -->
<view class="ciy-form">
<label class="char4">头像</label>
<view class="flex flex-center">
<image
:src="form.icon || '/lab/default-avatar.png'"
:src="form.icon || '/lab/lab.png'"
mode="aspectFill"
class="w-12 h-12 rounded-full mr3"
></image>
<button class="btn def sm" @click="chooseAvatar">选择图片</button>
</view>
</view>
<!-- 3. 头衔 -->
<view class="ciy-form">
<label class="char4">头衔</label>
<picker
mode="selector"
:range="titleOptions"
:range-key="'label'"
v-model="form.usertitle"
class="px2 py1 bg1 rounded w-full"
@change="handlePickerChange($event, 'usertitle')"
>
<view class="txt-left px2 py1">{{ getTitleText(form.usertitle) }}</view>
<view class="txt-left px2 py1">{{getPickerCurrentLabel('usertitle') }}</view>
</picker>
</view>
<!-- 4. 成员状态必填 -->
<view class="ciy-form">
<label class="imp char4">状态</label>
<picker
mode="selector"
:range="statusOptions"
:range-key="'label'"
v-model="form.role"
class="px2 py1 bg1 rounded w-full"
@change="handlePickerChange($event, 'role')"
required
>
<view class="txt-left px2 py1">{{ statusMap[form.role] }}</view>
<view class="txt-left px2 py1">{{ getPickerCurrentLabel('role') }}</view>
</picker>
</view>
<!-- 5. 学历 -->
<view class="ciy-form">
<label class="char4">学历</label>
<picker
mode="selector"
:range="educationOptions"
:range-key="'label'"
v-model="form.education"
class="px2 py1 bg1 rounded w-full"
@change="handlePickerChange($event, 'education')"
>
<view class="txt-left px2 py1">{{ educationMap[form.education] }}</view>
<view class="txt-left px2 py1">{{ getPickerCurrentLabel('education') }}</view>
</picker>
</view>
<!-- 6. 编号 -->
<view class="ciy-form">
<label class="char4">编号</label>
<input
@ -87,22 +73,18 @@
class="ciy-edit px2 py1 bg1 rounded"
/>
</view>
<!-- 7. 性别 -->
<view class="ciy-form">
<label class="char4">性别</label>
<picker
mode="selector"
:range="sexOptions"
:range-key="'label'"
v-model="form.sex"
class="px2 py1 bg1 rounded w-full"
@change="handlePickerChange($event, 'sex')"
>
<view class="txt-left px2 py1">{{ sexMap[form.sex] }}</view>
<view class="txt-left px2 py1">{{ getPickerCurrentLabel('sex') }}</view>
</picker>
</view>
<!-- 8. 加入日期 -->
<view class="ciy-form">
<label class="char4">加入日期</label>
<picker
@ -111,12 +93,11 @@
start="2000-01-01"
end="2100-12-31"
class="px2 py1 bg1 rounded w-full"
@change="handleDateChange"
>
<view class="txt-left px2 py1">{{ form.addtimesText || '请选择日期' }}</view>
</picker>
</view>
<!-- 9. 手机号 -->
<view class="ciy-form">
<label class="char4">手机号</label>
<input
@ -127,8 +108,6 @@
maxlength="11"
/>
</view>
<!-- 10. 邮箱 -->
<view class="ciy-form">
<label class="char4">邮箱</label>
<input
@ -138,21 +117,17 @@
class="ciy-edit px2 py1 bg1 rounded"
/>
</view>
<!-- 11. 密码默认初始密码 -->
<view class="ciy-form">
<label class="char4">初始密码</label>
<input
type="password"
v-model="form.password"
placeholder="默认123456"
placeholder="默认1"
class="ciy-edit px2 py1 bg1 rounded"
:value="form.password || '123456'"
:value="form.password || '1'"
/>
</view>
</form>
<!-- 表单提交按钮 -->
<view class="ciy-form-bottom mt4">
<button
class="btn man lgg long"
@ -170,23 +145,25 @@
export default {
data() {
return {
isSubmitting: false, //
isSubmitting: false,
form: {
name: '', //
icon: '', //
usertitle: 0, //
role: 30, //
education: 50, //
sn: '', //
sex: 90, //
addtimesText: '', //
addtimes: 0, //
mobile: '', //
email: '', //
password: '123456' //
laborgid: 0,
stpstatus: 10,
userlevel:10,
dvotecnt:0,
name: '',
icon: '',
usertitle: 0,
role: 30,
education: 50,
sn: '',
sex: 90,
addtimesText: '',
addtimes: 0,
mobile: '',
email: '',
password: '1'
},
// lab_user.sql
titleOptions: [
{ value: 0, label: '无头衔' },
{ value: 10, label: '主任' },
@ -215,29 +192,16 @@ export default {
{ value: 20, label: '女' },
{ value: 90, label: '其他' }
],
//
statusMap: { 10: '负责人', 20: '科研秘书', 30: '在册成员', 40: '历史成员', 50: '外部成员' },
educationMap: { 50: '本科', 60: '硕士', 70: '博士' },
sexMap: { 10: '男', 20: '女', 90: '其他' },
titleMap: { 0: '无头衔', 10: '主任', 20: '副主任', 30: '顾问', 40: '名誉主任', 50: '教授', 60: '副教授', 70: '讲师', 80: '研究员' }
};
},
watch: {
//
'form.addtimesText'(val) {
if (val) {
this.form.addtimes = new Date(val).getTime();
}
}
},
methods: {
//
goBack() {
uni.navigateBack({ delta: 1 });
},
// /
chooseAvatar() {
uni.chooseImage({
count: 1,
@ -245,47 +209,74 @@ export default {
sourceType: ['album', 'camera'],
success: (res) => {
const tempFilePath = res.tempFilePaths[0];
//
this.form.icon = tempFilePath;
}
});
},
handlePickerChange(e, type) {
const selectedIndex = Number(e.detail.value);
const optionMap = {
usertitle: this.titleOptions,
role: this.statusOptions,
education: this.educationOptions,
sex: this.sexOptions
};
const optionList = optionMap[type];
if (!optionList || !optionList[selectedIndex]) return;
this.form[type] = optionList[selectedIndex].value;
},
getPickerCurrentLabel(type) {
const optionMap = {
usertitle: this.titleOptions,
role: this.statusOptions,
education: this.educationOptions,
sex: this.sexOptions
};
const optionList = optionMap[type];
const currentValue = this.form[type];
if (!optionList) return '请选择';
// 3.
const currentOption = optionList.find(item => item.value === currentValue);
// 4.
return currentOption ? currentOption.label : '请选择';
},
handleDateChange(e) {
const selectedDate = e.detail.value;
this.form.addtimesText = selectedDate;
this.form.addtimes = new Date(selectedDate).getTime();
},
//
getTitleText(usertitle) {
return this.titleMap[usertitle] || '无头衔';
},
//
async submitForm() {
// 1.
if (!this.form.name) {
return uni.showToast({ title: '请输入成员姓名', icon: 'none' });
}
if (!this.form.addtimes) {
return uni.showToast({ title: '请选择加入日期', icon: 'none' });
}
// 2.
this.isSubmitting = true;
if (this.form.mobile && !/^1[3-9]\d{9}$/.test(this.form.mobile)) {
return uni.showToast({ title: '请输入有效的11位手机号', icon: 'none' });
}
if (this.form.email && !/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(this.form.email)) {
return uni.showToast({ title: '请输入有效的邮箱地址', icon: 'none' });
}
const postData = this.form;
try {
// 3.
console.log('提交的成员信息:', this.form);
// 4.
var retjson = await this.callfunc({
func: 'adduser.add',
data: postData
});
if (retjson.code !== 1) {
return uni.showToast({ title: retjson.msg || '新增成员失败', icon: 'none' });
}
uni.showToast({ title: '新增成员成功', icon: 'success' });
// 5.
setTimeout(() => {
this.goBack();
}, 1500);
console.log('提交的成员信息:', this.form);
} catch (err) {
uni.showToast({ title: '提交失败,请重试', icon: 'none' });
console.error('新增成员失败:', err);
} finally {
// 6.
this.isSubmitting = false;
}
}
}

View File

@ -1,6 +1,7 @@
<template>
<view class="ciy-page container">
<!-- 页面头部搜索栏 + 新增按钮 -->
<ciy-header title="成员管理" ref="header"></ciy-header>
<view class="main-header bg-white px4 py3 flex flex-center justify-between shadow-sm">
<!-- 搜索框区域 -->
<view class="search-container flex flex1 mr3 relative">
@ -88,7 +89,6 @@
</template>
<script>
import { request } from '@/util/request';
export default {
data() {
return {
@ -148,37 +148,37 @@ export default {
},
methods: {
//
async getMemberList(isAppend = false) {
//
const mockData = [
{ id: 1, name: '张三', usertitle: 10, role: 10 },
{ id: 2, name: '李四', usertitle: 50, role: 20 },
{ id: 3, name: '王五', usertitle: 80, role: 30 },
{ id: 4, name: '赵六', usertitle: 20, role: 40 },
{ id: 5, name: '孙七', usertitle: 60, role: 50 },
{ id: 6, name: '周八', usertitle: 70, role: 30 },
];
async getMemberList(isAppend = false) {
try {
//
const params = {
page: this.page,
pagesize: this.pageSize,
name: this.searchKey, // name
role: this.activeStatus || 0, // role
status: 0, // stpstatus
action: 'get_list' // member.php
};
// +
let filteredData = mockData.filter(item => {
const statusMatch = this.activeStatus === '' || item.role === this.activeStatus;
const searchMatch = item.name.includes(this.searchKey) || this.titleMap[item.usertitle].includes(this.searchKey);
return statusMatch && searchMatch;
});
//
const res = await request('/member.php', params);
//
const paginatedData = filteredData.slice((this.page - 1) * this.pageSize, this.page * this.pageSize);
//
const { list, total } = res;
if (isAppend) {
this.memberList = [...this.memberList, ...list];
} else {
this.memberList = list;
}
//
if (isAppend) {
this.memberList = [...this.memberList, ...paginatedData];
} else {
this.memberList = paginatedData;
}
//
this.hasMoreData = this.memberList.length < total;
} catch (err) {
console.error('获取成员列表失败:', err);
this.hasMoreData = false; //
}
},
//
this.hasMoreData = this.memberList.length < filteredData.length;
},
//
handleStatusChange(status) {
@ -307,7 +307,7 @@ async getMemberList(isAppend = false) {
.status-btn {
border: none;
font-weight: 500;
border-radius: 999px;
border-radius: 10px;
padding: 4px 12px; /* 缩小按钮内边距 */
margin-right: 8px; /* 缩小按钮间距 */
transition: all 0.3s ease;
@ -323,7 +323,6 @@ async getMemberList(isAppend = false) {
background-color: var(--gray-100);
}
/* 选中态样式(清晰可见,不冲突) */
.status-btn-active {
background-color: #165DFF !important;
color: #FFFFFF !important;

View File

@ -30,6 +30,30 @@
<view class="icon" :style="{backgroundImage:svg2bg(svg.cmh)}"></view>
<view class="name">原型演示</view>
</view>
<view class="grid" @tap="gourl" data-url="$/pages/lab/list">
<view class="icon" :style="{backgroundImage:svg2bg(svg.cmh)}"></view>
<view class="name">在研课题备案</view>
</view>
<view class="grid" @tap="gourl" data-url="$/pages/lab/list">
<view class="icon" :style="{backgroundImage:svg2bg(svg.cmh)}"></view>
<view class="name">组会管理</view>
</view>
<view class="grid" @tap="gourl" data-url="$/pages/lab/list">
<view class="icon" :style="{backgroundImage:svg2bg(svg.cmh)}"></view>
<view class="name">平等研讨</view>
</view>
<view class="grid" @tap="gourl" data-url="$/pages/lab/list">
<view class="icon" :style="{backgroundImage:svg2bg(svg.cmh)}"></view>
<view class="name">科研经费预审</view>
</view>
<view class="grid" @tap="gourl" data-url="$/pages/lab/list">
<view class="icon" :style="{backgroundImage:svg2bg(svg.cmh)}"></view>
<view class="name">科研成果登记</view>
</view>
<view class="grid" @tap="gourl" data-url="$/pages/lab/list">
<view class="icon" :style="{backgroundImage:svg2bg(svg.cmh)}"></view>
<view class="name">经验积累</view>
</view>
</view>
</view>
<view class="ciy-caption mk sti" :style="{top:(header_statusbar_height+header_title_height)+'px'}">

View File

@ -11,7 +11,7 @@
Target Server Version : 100510
File Encoding : 65001
Date: 29/01/2026 17:03:51
Date: 30/01/2026 00:44:12
*/
SET NAMES utf8mb4;
@ -42,6 +42,7 @@ CREATE TABLE `lab_user` (
`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',
`deletetimes` int(11) NULL DEFAULT NULL COMMENT '逻辑删除时间(时间戳)',
`ip` varchar(40) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '#登录IP,IP',
`role` int(11) NOT NULL COMMENT '成员状态:负责人,科研秘书,在册成员,外部人员,历史人员',
PRIMARY KEY (`id`) USING BTREE
@ -50,15 +51,15 @@ CREATE TABLE `lab_user` (
-- ----------------------------
-- Records of lab_user
-- ----------------------------
INSERT INTO `lab_user` VALUES (14, 1, '/lab/lab.png', '张三', 10, 70, 'LAB-2024-001', 20, 1700000000000, '13800138001', 'zhangsan@lab.com', 'd527d1bf5fe6a4361f230af48e36e1c4', 10, 30, 0, 120, 0, 1710000000000, '', 0, '192.168.1.101', 60);
INSERT INTO `lab_user` VALUES (15, 1, '/lab/lab.png', '李四', 50, 50, 'LAB-2024-002', 20, 1702000000000, '13900139002', 'lisi@lab.com', 'd527d1bf5fe6a4361f230af48e36e1c4', 10, 20, 0, 86, 11, 1769417475, '', 0, '192.168.1.102', 60);
INSERT INTO `lab_user` VALUES (16, 2, '/lab/lab.png', '王五', 80, 60, 'LAB-2024-003', 20, 1704000000000, '13700137003', 'wangwu@lab.com', 'd527d1bf5fe6a4361f230af48e36e1c4', 10, 10, 0, 45, 2, 1712000000000, '', 0, '192.168.1.103', 60);
INSERT INTO `lab_user` VALUES (17, 1, '/lab/lab.png', '赵六', 20, 60, 'LAB-2024-004', 10, 1706000000000, '13600136004', 'zhaoliu@lab.com', 'd527d1bf5fe6a4361f230af48e36e1c4', 10, 20, 0, 98, 0, 1713000000000, '', 0, '192.168.1.104', 60);
INSERT INTO `lab_user` VALUES (19, 0, '/lab/lab.png', ':3780', 0, 0, '', 90, 1769439652, '18248103780', '', 'd527d1bf5fe6a4361f230af48e36e1c4', 10, 10, 0, 0, 0, 1769671619, 'TM15jZmrBs', 1769675219, '127.0.0.1', 60);
INSERT INTO `lab_user` VALUES (20, 0, '/lab/lab.png', ':0022', 0, 0, '', 90, 1769445509, '13654880022', '', 'd527d1bf5fe6a4361f230af48e36e1c4', 10, 10, 0, 0, 0, 1769448199, 'p43i428v1j', 1769451799, '127.0.0.1', 60);
INSERT INTO `lab_user` VALUES (21, 0, '/lab/lab.png', ':0023', 0, 0, '', 90, 1769529209, '13654880023', '', 'd527d1bf5fe6a4361f230af48e36e1c4', 10, 10, 0, 0, 0, 1769529209, 'FuBzvhAHI5', 1769532809, '127.0.0.1', 60);
INSERT INTO `lab_user` VALUES (22, 0, '/lab/lab.png', ':3788', 0, 0, '', 90, 1769671931, '18248103788', '', 'd527d1bf5fe6a4361f230af48e36e1c4', 10, 10, 0, 0, 0, 1769672290, 'GjXvuqnEoM', 1769675890, '127.0.0.1', 60);
INSERT INTO `lab_user` VALUES (23, 0, '/lab/lab.png', ':3789', 0, 0, '', 90, 1769672770, '18248103789', '', 'd527d1bf5fe6a4361f230af48e36e1c4', 10, 10, 0, 0, 0, 1769674212, 'i49npHbGlL', 1769677812, '127.0.0.1', 60);
INSERT INTO `lab_user` VALUES (24, 0, '/lab/lab.png', ':0024', 0, 0, '', 90, 1769676173, '13654880024', '', 'd527d1bf5fe6a4361f230af48e36e1c4', 10, 10, 0, 0, 0, 1769676173, '1ZPWhJNtkd', 1769679773, '127.0.0.1', 60);
INSERT INTO `lab_user` VALUES (14, 1, '/lab/lab.png', '张三', 10, 70, 'LAB-2024-001', 20, 1700000000000, '13800138001', 'zhangsan@lab.com', 'd527d1bf5fe6a4361f230af48e36e1c4', 10, 30, 0, 120, 0, 1710000000000, '', 0, NULL, '192.168.1.101', 60);
INSERT INTO `lab_user` VALUES (15, 1, '/lab/lab.png', '李四', 50, 50, 'LAB-2024-002', 20, 1702000000000, '13900139002', 'lisi@lab.com', 'd527d1bf5fe6a4361f230af48e36e1c4', 10, 20, 0, 86, 11, 1769417475, '', 0, NULL, '192.168.1.102', 60);
INSERT INTO `lab_user` VALUES (16, 2, '/lab/lab.png', '王五', 80, 60, 'LAB-2024-003', 20, 1704000000000, '13700137003', 'wangwu@lab.com', 'd527d1bf5fe6a4361f230af48e36e1c4', 10, 10, 0, 45, 2, 1712000000000, '', 0, NULL, '192.168.1.103', 60);
INSERT INTO `lab_user` VALUES (17, 1, '/lab/lab.png', '赵六', 20, 60, 'LAB-2024-004', 10, 1706000000000, '13600136004', 'zhaoliu@lab.com', 'd527d1bf5fe6a4361f230af48e36e1c4', 10, 20, 0, 98, 0, 1713000000000, '', 0, NULL, '192.168.1.104', 60);
INSERT INTO `lab_user` VALUES (19, 0, '/lab/lab.png', ':3780', 0, 0, '', 90, 1769439652, '18248103780', '', 'd527d1bf5fe6a4361f230af48e36e1c4', 10, 10, 0, 0, 0, 1769696223, '7ohbWCmO87', 1769703976, NULL, '127.0.0.1', 60);
INSERT INTO `lab_user` VALUES (20, 0, '/lab/lab.png', ':0022', 0, 0, '', 90, 1769445509, '13654880022', '', 'd527d1bf5fe6a4361f230af48e36e1c4', 10, 10, 0, 0, 0, 1769448199, 'p43i428v1j', 1769451799, NULL, '127.0.0.1', 60);
INSERT INTO `lab_user` VALUES (21, 0, '/lab/lab.png', ':0023', 0, 0, '', 90, 1769529209, '13654880023', '', 'd527d1bf5fe6a4361f230af48e36e1c4', 10, 10, 0, 0, 0, 1769529209, 'FuBzvhAHI5', 1769532809, NULL, '127.0.0.1', 60);
INSERT INTO `lab_user` VALUES (22, 0, '/lab/lab.png', ':3788', 0, 0, '', 90, 1769671931, '18248103788', '', 'd527d1bf5fe6a4361f230af48e36e1c4', 10, 10, 0, 0, 0, 1769672290, 'GjXvuqnEoM', 1769675890, NULL, '127.0.0.1', 60);
INSERT INTO `lab_user` VALUES (23, 0, '/lab/lab.png', ':3789', 0, 0, '', 90, 1769672770, '18248103789', '', 'd527d1bf5fe6a4361f230af48e36e1c4', 10, 10, 0, 0, 0, 1769674212, 'i49npHbGlL', 1769677812, NULL, '127.0.0.1', 60);
INSERT INTO `lab_user` VALUES (24, 0, '/lab/lab.png', ':0024', 0, 0, '', 90, 1769676173, '13654880024', '', 'd527d1bf5fe6a4361f230af48e36e1c4', 10, 10, 0, 0, 0, 1769676173, '1ZPWhJNtkd', 1769679773, NULL, '127.0.0.1', 60);
SET FOREIGN_KEY_CHECKS = 1;

83
web/ambap/adduser.php Normal file
View File

@ -0,0 +1,83 @@
<?php
namespace web\ambap;
class adduser {
public static function json_add() {
$db = new \ciy\db();
$post = new \ciy\post();
$laborgid = $post->getint('laborgid', 0);
$stpstatus = 10;
$userlevel=10;
$dvotecnt=0;
$exptimes = 2147483647;
$name = $post->get('name');
$addtimes = $post->getint('addtimes');
$addtimesText = $post->get('addtimesText');
$icon = $post->get('icon', '');
$usertitle = $post->getint('usertitle', 0);
$role = $post->getint('role', 30);
$education = $post->getint('education', 50);
$sn = $post->get('sn', '');
$sex = $post->getint('sex', 90);
$mobile = $post->get('mobile', '');
$email = $post->get('email', '');
$password = $post->get('password', '1');
if (empty($name)) {
return errjson('请填写成员姓名');
}
if (empty($addtimes) || !is_numeric($addtimes)) {
return errjson('请选择有效的加入日期');
}
if (!empty($mobile)) {
if (!preg_match('/^1[3-9]\d{9}$/', $mobile)) {
return errjson('请输入有效的11位手机号');
}
}
if (!empty($email) && !filter_var($email, FILTER_VALIDATE_EMAIL)) {
return errjson('请输入有效的邮箱地址');
}
$addtimes = intval($addtimes / 1000);
$insertData = [
'laborgid' => $laborgid,
'stpstatus'=>$stpstatus,
'userlevel'=>$userlevel,
'name' => $name,
'dvotecnt'=>$dvotecnt,
'exptimes' => $exptimes,
'icon' => $icon,
'usertitle' => $usertitle,
'role' => $role,
'education' => $education,
'sn' => $sn,
'sex' => $sex,
'addtimes' => $addtimes,
'mobile' => $mobile,
'email' => $email,
'password' => md5($password),
'trytime' => 0,
'logintimes' => tostamp(),
'ip' => getip()
];
try {
$csql = new \ciy\sql('lab_user');
$insertResult = $db->insert($csql, $insertData);
if ($insertResult === false) {
return errjson('新增成员失败:' . $db->error);
}
$newMemberId = $db->insert_id();
$successData = [
'id' => $newMemberId,
'name' => $name
];
return succjson($successData);
} catch (\Exception $e) {
return errjson('新增成员失败:' . $e->getMessage());
}
}
}
adduser::json_add();

View File

@ -1,342 +0,0 @@
<?php
namespace web\ambap;
/**
* 依赖:全局$db对象、ciy\post、errjson/succjson、savelog、tostamp函数
*/
class member {
/**
* 获取成员列表(支持分页/筛选/字典值转换)
* @return array
*/
public static function json_get_list() {
global $db;
$post = new \ciy\post();
// 1. 初始化参数(解决未定义变量)
$page = $post->getint('page', 1); // 当前页
$pagesize = $post->getint('pagesize', 20); // 每页条数
$offset = ($page - 1) * $pagesize; // 偏移量
$mobile = trim($post->get('mobile', '')); // 手机号筛选
$name = trim($post->get('name', '')); // 姓名筛选
$status = $post->getint('status', 0); // 状态筛选
$role = $post->getint('role', 60); // 角色筛选
// 2. 构建SQL修复精简JOIN语句格式避免语法错误
$csql = new \ciy\sql("lab_user u
LEFT JOIN zc_cata s ON u.sex = s.codeid AND s.cbid = 10
LEFT JOIN zc_cata st ON u.stpstatus = st.codeid AND st.cbid = 11
LEFT JOIN zc_cata e ON u.education = e.codeid AND e.cbid = 102
LEFT JOIN zc_cata ut ON u.usertitle = ut.codeid AND ut.cbid = 12001701
LEFT JOIN zc_cata r ON u.role = r.codeid AND r.cbid = 12001703
LEFT JOIN zc_cata rr ON u.userlevel=rr.codeid AND rr.cbid=12001704");
// 配置查询字段(含字典关联中文名称)
$csql->column("u.id, u.mobile, u.name, u.usertitle, u.education, u.sex,
u.role, u.userlevel, u.stpstatus, u.addtimes, u.logintimes, u.ip,
s.name as sex_name, st.name as stpstatus_name, e.name as education_name,
ut.name as usertitle_name, r.name as role_name, rr.name as userlevel_name");
// 3. 拼接筛选条件
if (!empty($mobile)) {
$csql->where('u.mobile', $mobile);
}
if (!empty($name)) {
$csql->where('u.name', '%' . $name . '%', 'like');
}
if ($status > 0) {
$csql->where('u.stpstatus', $status);
}
if ($role > 0) {
$csql->where('u.role', $role);
}
// 4. 排序+分页(正确传参)
$csql->order('u.logintimes desc');
$csql->limit($offset, $pagesize);
// 5. 执行查询
$list = $db->get($csql);
if ($list === false) {
return errjson('查询成员列表失败: ' . $db->error);
}
// 6. 查询总数修复移除limit方法而非传0,0
$countSql = clone $csql;
$countSql->column('count(DISTINCT u.id) as total');
// 关键修复删除limit(0,0)ciy\sql默认无limit
$total = $db->get1($countSql);
// 7. 返回结果
return succjson([
'list' => $list ?: [],
'total' => $total ?: 0,
'page' => $page,
'pagesize' => $pagesize
]);
}
/**
* 获取成员详情(含字典中文名称)
* @return array
*/
public static function json_get_detail() {
global $db;
$post = new \ciy\post();
$id = $post->getint('id');
if ($id <= 0) {
return errjson('请传入有效的成员ID');
}
// 修复精简JOIN语句格式
$csql = new \ciy\sql("lab_user u
LEFT JOIN zc_cata s ON u.sex = s.codeid AND s.cbid = 10
LEFT JOIN zc_cata st ON u.stpstatus = st.codeid AND st.cbid = 11
LEFT JOIN zc_cata e ON u.education = e.codeid AND e.cbid = 102
LEFT JOIN zc_cata ut ON u.usertitle = ut.codeid AND ut.cbid = 12001701
LEFT JOIN zc_cata r ON u.role = r.codeid AND r.cbid = 12001703
LEFT JOIN zc_cata rr ON u.userlevel=rr.codeid AND rr.cbid=12001704");
$csql->column("u.*, s.name as sex_name, st.name as stpstatus_name,
e.name as education_name, ut.name as usertitle_name,
r.name as role_name, rr.name as userlevel_name");
$csql->where('u.id', $id);
$detail = $db->getone($csql);
if ($detail === false) {
return errjson('查询成员详情失败: ' . $db->error);
}
if (!is_array($detail)) {
return errjson('该成员不存在');
}
// 补充扩展信息(单表直接传构造函数)
$extSql = new \ciy\sql('ap_usr_ext');
$extSql->where('id', $id);
$extDetail = $db->getone($extSql);
if (is_array($extDetail)) {
$detail['appcid'] = $extDetail['appcid'];
}
return succjson($detail);
}
/**
* 编辑成员信息
* @return array
*/
public static function json_edit() {
global $db;
$post = new \ciy\post();
// 参数校验
$id = $post->getint('id');
$name = trim($post->get('name', ''));
$usertitle = $post->getint('usertitle', 0);
$education = $post->getint('education', 0);
$sex = $post->getint('sex', 90);
// 优化role默认值改为0避免无字典数据
$role = $post->getint('role', 0);
$userlevel = $post->getint('userlevel', 10);
if ($id <= 0) {
return errjson('请传入有效的成员ID');
}
if (empty($name)) {
return errjson('请填写成员姓名');
}
// 组装更新数据
$updata = [
'name' => $name,
'usertitle' => $usertitle,
'education' => $education,
'sex' => $sex,
'role' => $role,
'userlevel' => $userlevel
];
// 单表操作:构造函数直接传表名
$csql = new \ciy\sql('lab_user');
$csql->where('id', $id);
$res = $db->update($csql, $updata);
if ($res === false) {
savelog($db, 0, 'MEMBEREDIT', '编辑成员[' . $id . ']失败: ' . $db->error);
return errjson('编辑成员失败: ' . $db->error);
}
savelog($db, $id, 'MEMBEREDIT', '编辑成员[' . $id . ']成功');
return succjson(['msg' => '编辑成功']);
}
/**
* 禁用/启用成员
* @return array
*/
public static function json_change_status() {
global $db;
$post = new \ciy\post();
$id = $post->getint('id');
$status = $post->getint('status');
if ($id <= 0) {
return errjson('请传入有效的成员ID');
}
$updata = ['stpstatus' => $status];
$csql = new \ciy\sql('lab_user');
$csql->where('id', $id);
$res = $db->update($csql, $updata);
if ($res === false) {
$action = $status == 10 ? '启用' : '禁用';
savelog($db, 0, 'MEMBERSTATUS', $action . '成员[' . $id . ']失败: ' . $db->error);
return errjson($action . '成员失败: ' . $db->error);
}
$action = $status == 10 ? '启用' : '禁用';
savelog($db, $id, 'MEMBERSTATUS', $action . '成员[' . $id . ']成功');
return succjson(['msg' => $action . '成功']);
}
/**
* 逻辑删除成员标记deletetimes
* @return array
*/
public static function json_delete() {
global $db;
$post = new \ciy\post();
$id = $post->getint('id');
if ($id <= 0) {
return errjson('请传入有效的成员ID');
}
// 逻辑删除:标记删除时间+禁用状态
$updata = [
'stpstatus' => 99, // 99:已删除
'deletetimes' => tostamp() // 时间戳
];
$csql = new \ciy\sql('lab_user');
$csql->where('id', $id);
$res = $db->update($csql, $updata);
if ($res === false) {
savelog($db, 0, 'MEMBERDELETE', '删除成员[' . $id . ']失败: ' . $db->error);
return errjson('删除成员失败: ' . $db->error);
}
savelog($db, $id, 'MEMBERDELETE', '删除成员[' . $id . ']成功');
return succjson(['msg' => '删除成功']);
}
/**
* 重置成员密码(和登录逻辑一致)
* @return array
*/
public static function json_reset_pass() {
global $db;
global $_token; // 确保全局_token包含salt
$post = new \ciy\post();
$id = $post->getint('id');
$newPass = trim($post->get('new_pass', ''));
if ($id <= 0) {
return errjson('请传入有效的成员ID');
}
if (empty($newPass)) {
return errjson('请填写新密码');
}
// 优化:校验$_token是否存在
if (empty($_token) || empty($_token['salt'])) {
return errjson('密码加密配置异常,请联系管理员');
}
// 密码加密(和注册逻辑对齐)
$encryptPass = md5($newPass . $_token['salt']);
$updata = [
'password' => $encryptPass,
'trytime' => 0 // 重置错误尝试次数
];
$csql = new \ciy\sql('lab_user');
$csql->where('id', $id);
$res = $db->update($csql, $updata);
if ($res === false) {
savelog($db, 0, 'MEMBERRESETPASS', '重置成员[' . $id . ']密码失败: ' . $db->error);
return errjson('重置密码失败: ' . $db->error);
}
savelog($db, $id, 'MEMBERRESETPASS', '重置成员[' . $id . ']密码成功');
return succjson(['msg' => '重置密码成功']);
}
/**
* 获取字典表数据(用于前端下拉选项)
* @return array
*/
public static function json_get_cata() {
global $db;
$post = new \ciy\post();
$cbid = $post->getint('cbid');
if ($cbid <= 0) {
return errjson('请传入有效的字典分类ID');
}
$csql = new \ciy\sql('zc_cata');
$csql->where('cbid', $cbid);
$csql->order('codeid asc');
$list = $db->get($csql);
if ($list === false) {
return errjson('查询字典失败: ' . $db->error);
}
return succjson(['list' => $list ?: []]);
}
}
global $db;
$post = new \ciy\post();
$action = trim($post->get('action', ''));
$result = [];
// 根据action调用对应方法
switch ($action) {
case 'get_list':
$result = member::json_get_list();
break;
case 'get_detail':
$result = member::json_get_detail();
break;
case 'edit':
$result = member::json_edit();
break;
case 'change_status':
$result = member::json_change_status();
break;
case 'delete':
$result = member::json_delete();
break;
case 'reset_pass':
$result = member::json_reset_pass();
break;
case 'get_cata':
$result = member::json_get_cata();
break;
default:
$result = errjson('无效的接口操作: ' . $action);
}
// 输出JSON结果前端才能接收数据
header('Content-Type: application/json; charset=utf-8');
echo json_encode($result, JSON_UNESCAPED_UNICODE);
exit;