1.将部门修改为渠道,并且所有dice_表关联渠道表

2.将所有配置表,记录表设置关联渠道
3.优化后台页面设置
This commit is contained in:
2026-05-19 09:49:02 +08:00
parent 085454fb78
commit dd264b1e97
143 changed files with 4741 additions and 1254 deletions

View File

@@ -0,0 +1,257 @@
<?php
declare(strict_types=1);
namespace plugin\saiadmin\app\service;
use plugin\saiadmin\app\model\system\SystemDept;
use plugin\saiadmin\app\model\system\SystemRole;
use plugin\saiadmin\exception\ApiException;
use support\think\Db;
/**
* 渠道角色:从默认模板复制指定角色、同步与删除
*/
class SystemRoleChannelService
{
/** 全局超级管理员角色,不参与渠道复制 */
public const SUPER_ADMIN_ROLE_ID = 1;
/**
* 为渠道从默认模板复制三个代理角色(缺失则补齐,不整包跳过)
*/
public function copyDefaultRolesToDept(int $deptId, bool $pruneExtra = false): array
{
if ($deptId <= 0) {
throw new ApiException('Invalid channel id');
}
if (!$this->tableHasColumn('sa_system_role', 'dept_id')) {
return ['dept_id' => $deptId, 'copied' => 0, 'skipped' => 0, 'pruned' => 0, 'message' => 'dept_id column missing'];
}
$templates = $this->defaultTemplateRoles();
if (empty($templates)) {
return ['dept_id' => $deptId, 'copied' => 0, 'skipped' => 0, 'pruned' => 0, 'message' => 'no template roles'];
}
$copied = 0;
$skipped = 0;
foreach ($templates as $template) {
$template = (array) $template;
$templateId = (int) ($template['id'] ?? 0);
$code = (string) ($template['code'] ?? '');
if ($templateId <= 0 || $code === '') {
continue;
}
if ($this->roleExists($deptId, $code)) {
$skipped++;
continue;
}
$newId = $this->insertRoleFromTemplate($template, $deptId);
if ($newId > 0) {
$this->copyRoleMenus($templateId, $newId);
$copied++;
}
}
$pruned = 0;
if ($pruneExtra) {
$pruned = $this->pruneExtraChannelRoles($deptId);
}
return ['dept_id' => $deptId, 'copied' => $copied, 'skipped' => $skipped, 'pruned' => $pruned];
}
/**
* 为所有已启用渠道补齐三个默认角色,并移除多余历史角色
*/
public function syncAllChannelsFromDefault(): array
{
$deptIds = SystemDept::where('status', 1)->where('id', '>', 0)->column('id');
$result = [];
foreach ($deptIds as $deptId) {
$result[(int) $deptId] = $this->copyDefaultRolesToDept((int) $deptId, true);
}
return $result;
}
/**
* 删除渠道下全部角色及菜单关联
*/
public function deleteRolesByDept(int $deptId): int
{
if ($deptId <= 0) {
return 0;
}
$roleIds = SystemRole::where('dept_id', $deptId)->column('id');
if (empty($roleIds)) {
return 0;
}
Db::name('sa_system_user_role')->whereIn('role_id', $roleIds)->delete();
Db::name('sa_system_role_menu')->whereIn('role_id', $roleIds)->delete();
Db::name('sa_system_role_dept')->whereIn('role_id', $roleIds)->delete();
return SystemRole::destroy($roleIds);
}
/**
* 将用户已绑定的模板角色映射到其渠道对应角色(仅三个默认 code
*/
public function remapUserRolesToChannelRoles(): int
{
if (!$this->tableHasColumn('sa_system_role', 'dept_id')) {
return 0;
}
$codes = $this->getDefaultChannelRoleCodes();
if (empty($codes)) {
return 0;
}
$codeList = "'" . implode("','", array_map('addslashes', $codes)) . "'";
return Db::execute(
'UPDATE `sa_system_user_role` ur
INNER JOIN `sa_system_user` u ON ur.user_id = u.id
INNER JOIN `sa_system_role` r_old ON ur.role_id = r_old.id
INNER JOIN `sa_system_role` r_new ON r_new.dept_id = u.dept_id AND r_new.code = r_old.code
SET ur.role_id = r_new.id
WHERE u.dept_id > 0
AND r_old.dept_id = 0
AND r_old.code IN (' . $codeList . ')
AND r_old.id <> ' . self::SUPER_ADMIN_ROLE_ID
);
}
/**
* @return string[]
*/
public function getDefaultChannelRoleCodes(): array
{
$codes = config('plugin.saiadmin.saithink.channel_default_role_codes', []);
if (!is_array($codes) || $codes === []) {
return ['yijidaili', 'erjidaili', 'sanjidaili'];
}
$out = [];
foreach ($codes as $code) {
$code = trim((string) $code);
if ($code !== '') {
$out[] = $code;
}
}
return $out;
}
/**
* 删除渠道下不在默认三个 code 内、且未被用户绑定的角色
*/
public function pruneExtraChannelRoles(int $deptId): int
{
if ($deptId <= 0) {
return 0;
}
$allowed = $this->getDefaultChannelRoleCodes();
if (empty($allowed)) {
return 0;
}
$query = SystemRole::where('dept_id', $deptId)->whereNotIn('code', $allowed);
$roleIds = $query->column('id');
if (empty($roleIds)) {
return 0;
}
$usedIds = Db::name('sa_system_user_role')->whereIn('role_id', $roleIds)->column('role_id');
$usedMap = array_flip($usedIds ?: []);
$pruned = 0;
foreach ($roleIds as $roleId) {
if (isset($usedMap[$roleId])) {
continue;
}
Db::name('sa_system_role_menu')->where('role_id', $roleId)->delete();
Db::name('sa_system_role_dept')->where('role_id', $roleId)->delete();
SystemRole::destroy($roleId);
$pruned++;
}
return $pruned;
}
/**
* @return array<int, array<string, mixed>>
*/
private function defaultTemplateRoles(): array
{
$codes = $this->getDefaultChannelRoleCodes();
if (empty($codes)) {
return [];
}
$query = Db::table('sa_system_role')
->where('id', '<>', self::SUPER_ADMIN_ROLE_ID)
->whereIn('code', $codes);
if ($this->tableHasColumn('sa_system_role', 'dept_id')) {
$query->where('dept_id', 0);
}
$rows = $query->order('sort', 'desc')->select()->toArray();
if (count($rows) === count($codes)) {
return $rows;
}
// 按配置顺序返回,缺失的 code 跳过
$byCode = [];
foreach ($rows as $row) {
$byCode[(string) ($row['code'] ?? '')] = $row;
}
$ordered = [];
foreach ($codes as $code) {
if (isset($byCode[$code])) {
$ordered[] = $byCode[$code];
}
}
return $ordered;
}
private function insertRoleFromTemplate(array $template, int $deptId): int
{
unset(
$template['id'],
$template['create_time'],
$template['update_time'],
$template['delete_time']
);
$template['dept_id'] = $deptId;
$now = date('Y-m-d H:i:s');
if (!isset($template['create_time'])) {
$template['create_time'] = $now;
}
if (!isset($template['update_time'])) {
$template['update_time'] = $now;
}
return (int) Db::table('sa_system_role')->insertGetId($template);
}
private function copyRoleMenus(int $fromRoleId, int $toRoleId): void
{
$menuIds = Db::name('sa_system_role_menu')->where('role_id', $fromRoleId)->column('menu_id');
if (empty($menuIds)) {
return;
}
$rows = [];
foreach ($menuIds as $menuId) {
$rows[] = ['role_id' => $toRoleId, 'menu_id' => $menuId];
}
Db::name('sa_system_role_menu')->limit(100)->insertAll($rows);
}
private function roleExists(int $deptId, string $code): bool
{
return SystemRole::where('dept_id', $deptId)->where('code', $code)->count() > 0;
}
private function tableHasColumn(string $table, string $column): bool
{
try {
$fields = Db::getFields($table);
return isset($fields[$column]);
} catch (\Throwable $e) {
return false;
}
}
}