<?php
namespace app\admin\controller;
use ba\Random;
use Throwable;
use app\common\controller\Backend;
use think\facade\Db;
class Member extends Backend
{
protected object $model;
protected array|string $preExcludeFields = ['id', 'email', 'mobile', 'login_failure', 'last_login_time', 'last_login_ip', 'salt', 'motto', 'update_time', 'create_time', 'user_path'];
protected array $withJoinTable = ['pidTable'];
protected string|array $quickSearchField = ['username', 'nickname', 'id'];
public function initialize(): void
{
parent::initialize();
$this->model = new \app\admin\model\Member;
}
public function index(): void
{
if ($this->request->param('select')) {
$this->select();
}
list($where, $alias, $limit, $order) = $this->queryBuilder();
$res = $this->model
->withJoin($this->withJoinTable, $this->withJoinType)
->alias($alias)
->where($where)
->order($order)
->paginate($limit);
$res->visible(['pidTable' => ['username']]);
$this->success('', [
'list' => $res->items(),
'total' => $res->total(),
'remark' => get_route_remark(),
]);
}
public function add(): void
{
if ($this->request->isPost()) {
$data = $this->request->post();
if (!$data) {
$this->error(__('Parameter %s can not be empty', ['']));
}
$data = $this->excludeFields($data);
if ($this->dataLimit && $this->dataLimitFieldAutoFill) {
$data[$this->dataLimitField] = $this->auth->id;
}
$result = false;
$this->model->startTrans();
try {
if ($this->modelValidate) {
$validate = str_replace("\\model\\", "\\validate\\", get_class($this->model));
if (class_exists($validate)) {
$validate = new $validate;
if ($this->modelSceneValidate) $validate->scene('add');
$validate->check($data);
}
}
$salt = Random::build('alnum', 16);
$passwd = encrypt_password($data['password'], $salt);
$insert = [];
$insert['salt'] = $salt;
$insert['password'] = $passwd;
$insert['nickname'] = trim($data['nickname']);
$insert['username'] = trim($data['username']);
$insert['createtime'] = time();
$result = $this->model->save($insert);
$group_arr = [$data['group_id']];
if ($group_arr) {
$groupAccess = [];
foreach ($group_arr as $data) {
$groupAccess[] = [
'uid' => $this->model->id,
'group_id' => $data,
];
}
Db::name('admin_group_access')->insertAll($groupAccess);
}
$this->model->commit();
} catch (Throwable $e) {
$this->model->rollback();
$this->error($e->getMessage());
}
if ($result !== false) {
$this->success(__('Added successfully'));
} else {
$this->error(__('No rows were added'));
}
}
$this->error(__('Parameter error'));
}
}
<?php
namespace app\admin\validate;
use think\Validate;
class Member extends Validate
{
protected $failException = true;
protected $rule = [
'username' => 'require|regex:/^[a-zA-Z][a-zA-Z0-9_]{2,15}$/|unique:admin',
'nickname' => 'require',
'password' => 'require|regex:/^(?!.*[&<>"\'\n\r]).{6,32}$/',
'group_id' => 'require',
'pid' => 'require|integer'
];
protected $message = [
'username.require' => '用户名不能为空',
'username.regex' => '用户名必须以字母开头,只能包含字母、数字和下划线,长度在3-16之间',
'username.unique' => '用户名已存在',
'nickname.require' => '昵称不能为空',
'password.require' => '密码不能为空',
'password.regex' => '密码必须在6-32位之间,且不能包含特殊字符',
'group_id.require' => '角色ID不能为空',
'pid.require' => '父ID不能为空',
'pid.integer' => '父ID必须是整数',
];
protected $field = [
'username' => '用户名',
'nickname' => '昵称',
'password' => '密码',
'group_id' => '角色ID',
'pid' => '父ID',
];
protected $scene = [
'add' => ['username', 'nickname', 'password', 'pid', 'group_id'],
];
public function __construct()
{
parent::__construct();
}
}
<?php
namespace app\admin\model;
use think\Model;
class Member extends Model
{
protected $name = 'admin';
protected $autoWriteTimestamp = true;
public function pidTable(): \think\model\relation\BelongsTo
{
return $this->belongsTo(\app\admin\model\Admin::class, 'pid', 'id');
}
}
<template>
<div class="default-main ba-table-box">
<el-alert class="ba-table-alert" v-if="baTable.table.remark" :title="baTable.table.remark" type="info" show-icon />
<TableHeader
:buttons="['refresh', 'add', 'edit', 'delete', 'comSearch', 'quickSearch', 'columnDisplay']"
:quick-search-placeholder="t('Quick search placeholder', { fields: t('member.quick Search Fields') })"
></TableHeader>
<Table ref="tableRef"></Table>
<PopupForm />
</div>
</template>
<script setup lang="ts">
import { ref, provide, onMounted } from 'vue'
import baTableClass from '/@/utils/baTable'
import { defaultOptButtons } from '/@/components/table'
import { baTableApi } from '/@/api/common'
import { useI18n } from 'vue-i18n'
import PopupForm from './popupForm.vue'
import Table from '/@/components/table/index.vue'
import TableHeader from '/@/components/table/header/index.vue'
defineOptions({
name: 'member',
})
const { t } = useI18n()
const tableRef = ref()
const optButtons: OptButton[] = defaultOptButtons(['edit', 'delete'])
const baTable = new baTableClass(
new baTableApi('/admin/Member/'),
{
pk: 'id',
column: [
{ type: 'selection', align: 'center', operator: false },
{ label: t('member.username'), prop: 'username', align: 'center', operatorPlaceholder: t('Fuzzy query'), operator: 'LIKE', sortable: false },
{ label: t('member.nickname'), prop: 'nickname', align: 'center', operatorPlaceholder: t('Fuzzy query'), operator: 'LIKE', sortable: false },
{ label: t('member.avatar'), prop: 'avatar', align: 'center', render: 'image', operator: false },
{ label: t('member.status'), prop: 'status', align: 'center', render: 'tag', operator: false, sortable: false, replaceValue: { '0': t('member.status 0'), '1': t('member.status 1') } },
{ label: "上级用户", prop: 'pidTable.username', align: 'center', operatorPlaceholder: t('Fuzzy query'), render: 'tags', operator: 'LIKE' },
{ label: t('member.pid'), prop: 'pid', align: 'center', operator: 'eq', show:false },
{ label: t('member.create_time'), prop: 'create_time', align: 'center', render: 'datetime', operator: false, sortable: 'custom', width: 160, timeFormat: 'yyyy-mm-dd hh:MM:ss' },
{ label: t('Operate'), align: 'center', width: 100, render: 'buttons', buttons: optButtons, operator: false },
],
dblClickNotEditColumn: [undefined],
},
{
defaultItems: { status: '1' },
}
)
provide('baTable', baTable)
onMounted(() => {
baTable.table.ref = tableRef.value
baTable.mount()
baTable.getIndex()?.then(() => {
baTable.initSort()
baTable.dragSort()
})
})
</script>
<style scoped lang="scss"></style>