| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823 |
- <?php
- namespace app\admin\controller;
- use app\common\controller\Backend;
- use think\Cache;
- use think\Db;
- use think\exception\PDOException;
- use think\exception\ValidateException;
- use Exception;
- /**
- * 协助采购 — 通知公告
- *
- * @icon fa fa-bullhorn
- */
- class Purchasecontent extends Backend
- {
- /** 投递接收人可选范围:auth_group 根组 id(含其全部子组) */
- protected const RECIPIENT_AUTH_GROUP_ROOT_ID = 10;
- /** 表结构已就绪缓存键(避免每次请求重复 SHOW COLUMNS / 探表) */
- protected const SCHEMA_CACHE_KEY = 'purchase_content_schema_v2';
- /** 可选接收人列表缓存秒数 */
- protected const RECIPIENT_LIST_CACHE_TTL = 300;
- /** @var \app\admin\model\Purchasecontent */
- protected $model = null;
- protected $searchFields = 'subject,content';
- protected $noNeedRight = ['adminselect', 'install'];
- public function _initialize()
- {
- parent::_initialize();
- $this->model = new \app\admin\model\Purchasecontent;
- if (!Cache::get(self::SCHEMA_CACHE_KEY)) {
- $this->ensurePurchaseContentSchemaOnce();
- }
- }
- /** 首次访问时建表/迁移,完成后写入缓存 */
- protected function ensurePurchaseContentSchemaOnce(): void
- {
- $this->ensurePurchaseContentTables();
- $this->ensurePurchaseContentDatetimeColumns();
- Cache::set(self::SCHEMA_CACHE_KEY, 1);
- }
- protected function ensurePurchaseContentTables(): void
- {
- try {
- Db::query('SELECT 1 FROM `purchase_content` LIMIT 1');
- Db::query('SELECT 1 FROM `purchase_content_recipient` LIMIT 1');
- } catch (\Throwable $e) {
- $sqlFile = APP_PATH . 'extra' . DS . 'purchase_content_install.sql';
- if (is_file($sqlFile)) {
- $sql = file_get_contents($sqlFile);
- if (is_string($sql) && $sql !== '') {
- foreach (preg_split('/;\s*[\r\n]+/', $sql) as $stmt) {
- $stmt = trim($stmt);
- if ($stmt === '' || stripos($stmt, 'CREATE TABLE') === false) {
- continue;
- }
- try {
- Db::execute($stmt);
- } catch (\Throwable $ignore) {
- }
- }
- }
- }
- }
- }
- /** 旧版 int 时间戳列迁移为 datetime */
- protected function ensurePurchaseContentDatetimeColumns(): void
- {
- try {
- $this->migrateTableDatetimeColumn('purchase_content', 'createtime', '投递时间');
- $this->migrateTableDatetimeColumn('purchase_content', 'updatetime', '更新时间');
- $this->migrateTableDatetimeColumn('purchase_content_recipient', 'createtime', '创建时间');
- $this->migrateTableDatetimeColumn('purchase_content_recipient', 'read_time', '首次阅读时间');
- } catch (\Throwable $e) {
- }
- }
- protected function migrateTableDatetimeColumn(string $table, string $column, string $comment): void
- {
- $rows = Db::query("SHOW COLUMNS FROM `{$table}` LIKE '{$column}'");
- if (!is_array($rows) || !isset($rows[0]['Type'])) {
- return;
- }
- $type = strtolower((string)$rows[0]['Type']);
- if (strpos($type, 'int') === false) {
- return;
- }
- $tmp = $column . '_dt';
- Db::execute("ALTER TABLE `{$table}` ADD COLUMN `{$tmp}` datetime DEFAULT NULL COMMENT '{$comment}'");
- Db::execute("UPDATE `{$table}` SET `{$tmp}` = IF(`{$column}` > 0, FROM_UNIXTIME(`{$column}`), NULL)");
- Db::execute("ALTER TABLE `{$table}` DROP COLUMN `{$column}`");
- Db::execute("ALTER TABLE `{$table}` CHANGE `{$tmp}` `{$column}` datetime DEFAULT NULL COMMENT '{$comment}'");
- }
- /**
- * 投递/阅读时间展示:YYYY-MM-DD HH:mm:ss
- *
- * @param mixed $value
- */
- protected function formatPurchaseContentTime($value): string
- {
- if ($value === null || $value === '') {
- return '';
- }
- if (is_numeric($value)) {
- $ts = (int)$value;
- if ($ts > 946684800) {
- return date('Y-m-d H:i:s', $ts);
- }
- return '';
- }
- $s = trim((string)$value);
- if ($s === '' || stripos($s, '0000-00-00') === 0) {
- return '';
- }
- if (preg_match('/^(\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2})/', $s, $m)) {
- return $m[1];
- }
- if (preg_match('/^(\d{4}-\d{2}-\d{2})/', $s, $m)) {
- return $m[1] . ' 00:00:00';
- }
- $ts = strtotime($s);
- return ($ts !== false && $ts > 0) ? date('Y-m-d H:i:s', $ts) : $s;
- }
- /**
- * 选择后台用户(发送人 / 接收人)
- */
- public function adminselect()
- {
- $this->model = model('Admin');
- $this->selectpageFields = 'id,username,nickname';
- $this->searchFields = 'id,username,nickname';
- $groupIds = $this->loadRecipientAuthGroupIds();
- $this->model->where('status', 'normal');
- if ($groupIds !== []) {
- $this->model->where('id', 'in', function ($query) use ($groupIds) {
- $query->name('auth_group_access')->where('group_id', 'in', $groupIds)->field('uid');
- });
- } else {
- $this->model->where('id', 0);
- }
- return $this->selectpage();
- }
- public function index()
- {
- $this->relationSearch = false;
- $this->request->filter(['strip_tags', 'trim']);
- if (!$this->request->isAjax()) {
- return $this->view->fetch();
- }
- $adminId = (int)$this->auth->id;
- $isSuper = $this->auth->isSuperAdmin();
- list($where, $sort, $order, $offset, $limit) = $this->buildparams();
- $orderDir = strtoupper((string)$order) === 'ASC' ? 'ASC' : 'DESC';
- $sortField = preg_match('/^[a-zA-Z0-9_]+$/', (string)$sort) ? (string)$sort : 'id';
- $query = $this->model->where($where);
- if (!$isSuper) {
- $recvIds = Db::table('purchase_content_recipient')
- ->where('admin_id', $adminId)
- ->column('content_id');
- $recvIds = is_array($recvIds) ? array_values(array_unique(array_filter(array_map('intval', $recvIds)))) : [];
- $query->where(function ($q) use ($adminId, $recvIds) {
- $q->where('creator_id', $adminId);
- if ($recvIds !== []) {
- $q->whereOr('id', 'in', $recvIds);
- }
- });
- }
- $this->applyPurchaseContentSort($query, $sortField, $orderDir, $adminId);
- $list = $query->paginate($limit);
- $rows = $list->items();
- $this->enrichContentRows($rows, $adminId);
- return json(['total' => $list->total(), 'rows' => $rows]);
- }
- /**
- * 列表排序(支持投递人/投递给/状态等衍生字段)
- *
- * @param mixed $query
- */
- protected function applyPurchaseContentSort($query, string $sortField, string $orderDir, int $adminId): void
- {
- $table = $this->model->getTable();
- if ($sortField === 'sender_name') {
- $query->orderRaw(
- '(SELECT COALESCE(NULLIF(TRIM(sa.nickname), \'\'), sa.username, \'\') '
- . 'FROM admin sa WHERE sa.id = `' . $table . '`.sender_id LIMIT 1) ' . $orderDir
- )->order($table . '.id', 'DESC');
- return;
- }
- if ($sortField === 'recipient_names') {
- $query->orderRaw(
- '(SELECT COUNT(*) FROM purchase_content_recipient rcnt WHERE rcnt.content_id = `' . $table . '`.id) ' . $orderDir
- )->order($table . '.id', 'DESC');
- return;
- }
- if ($sortField === 'is_read') {
- $aid = max(0, $adminId);
- $query->orderRaw(
- '(SELECT CASE '
- . 'WHEN COUNT(*) = 0 THEN 2 '
- . 'WHEN SUM(CASE WHEN rr.read_time IS NULL OR rr.read_time = \'\' '
- . 'OR CAST(rr.read_time AS CHAR) LIKE \'0000-%\' THEN 1 ELSE 0 END) > 0 THEN 0 '
- . 'ELSE 1 END '
- . 'FROM purchase_content_recipient rr '
- . 'WHERE rr.content_id = `' . $table . '`.id AND rr.admin_id = ' . $aid . ') ' . $orderDir
- )->order($table . '.id', 'DESC');
- return;
- }
- $allow = ['id', 'createtime', 'subject', 'content', 'sender_id', 'creator_id', 'updatetime'];
- if (!in_array($sortField, $allow, true)) {
- $sortField = 'id';
- }
- $query->order($table . '.' . $sortField, $orderDir);
- }
- public function add()
- {
- if (!$this->request->isPost()) {
- $admin = $this->auth->getUserinfo();
- $this->view->assign('admin', [
- 'id' => (int)($admin['id'] ?? $this->auth->id),
- 'nickname' => (string)($admin['nickname'] ?? $admin['username'] ?? ''),
- ]);
- $this->view->assign('adminList', $this->loadNormalAdminList());
- return $this->view->fetch();
- }
- $params = $this->request->post('row/a');
- if (empty($params)) {
- $this->error(__('Parameter %s can not be empty', ''));
- }
- $subject = trim((string)($params['subject'] ?? ''));
- $content = trim((string)($params['content'] ?? ''));
- if ($subject === '') {
- $this->error('请填写主题');
- }
- if ($content === '') {
- $this->error('请填写内容');
- }
- $senderId = (int)$this->auth->id;
- if ($senderId <= 0 || !$this->adminExists($senderId)) {
- $this->error('当前登录用户无效');
- }
- $recipientIds = $this->parseRecipientIdList($params['recipient_ids'] ?? '');
- if ($recipientIds === []) {
- $this->error('请选择投递接收人');
- }
- $creatorId = (int)$this->auth->id;
- $now = date('Y-m-d H:i:s');
- Db::startTrans();
- try {
- $contentId = (int)Db::table('purchase_content')->insertGetId([
- 'creator_id' => $creatorId,
- 'sender_id' => $senderId,
- 'subject' => $subject,
- 'content' => $content,
- 'createtime' => $now,
- 'updatetime' => $now,
- ]);
- if ($contentId <= 0) {
- throw new Exception('保存公告失败');
- }
- $recvRows = [];
- foreach ($recipientIds as $aid) {
- $recvRows[] = [
- 'content_id' => $contentId,
- 'admin_id' => $aid,
- 'createtime' => $now,
- ];
- }
- Db::table('purchase_content_recipient')->insertAll($recvRows);
- Db::commit();
- } catch (ValidateException|PDOException|Exception $e) {
- Db::rollback();
- $this->error($e->getMessage());
- }
- $this->success();
- }
- public function detail($ids = null)
- {
- $row = $this->getContentRowForAdmin((int)$ids);
- if (!$row) {
- $this->error(__('No Results were found'));
- }
- $adminId = (int)$this->auth->id;
- $contentId = (int)$row['id'];
- $isCreator = (int)($row['creator_id'] ?? 0) === $adminId;
- $recvRow = Db::table('purchase_content_recipient')
- ->where('content_id', $contentId)
- ->where('admin_id', $adminId)
- ->find();
- $isReceiver = (bool)$recvRow;
- if (!$this->auth->isSuperAdmin() && !$isCreator && !$isReceiver) {
- $this->error('无权查看该通知');
- }
- // 当前用户是接收人时,首次查看标记为已读
- if ($recvRow) {
- $rt = $recvRow['read_time'] ?? null;
- $unread = ($rt === null || $rt === '' || stripos((string)$rt, '0000-00-00') === 0);
- if ($unread) {
- Db::table('purchase_content_recipient')
- ->where('id', (int)$recvRow['id'])
- ->update(['read_time' => date('Y-m-d H:i:s')]);
- }
- }
- $items = [$row];
- $this->enrichContentRows($items, $adminId);
- $row = $items[0];
- $this->view->assign('row', $row);
- return $this->view->fetch();
- }
- public function del($ids = null)
- {
- if (!$this->request->isPost()) {
- $this->error(__('Invalid parameters'));
- }
- $ids = $ids ?: $this->request->post('ids');
- $idList = $this->parseIdList($ids);
- if ($idList === []) {
- $this->error(__('Parameter %s can not be empty', 'ids'));
- }
- $adminId = (int)$this->auth->id;
- Db::startTrans();
- try {
- foreach ($idList as $cid) {
- $row = $this->model->get($cid);
- if (!$row) {
- continue;
- }
- if ((int)$row['sender_id'] !== $adminId) {
- throw new Exception('仅可删除本人投递的公告');
- }
- Db::table('purchase_content_recipient')->where('content_id', $cid)->delete();
- $row->delete();
- }
- Db::commit();
- } catch (PDOException|Exception $e) {
- Db::rollback();
- $this->error($e->getMessage());
- }
- $this->success();
- }
- /**
- * 安装菜单(超级管理员执行一次)
- */
- public function install()
- {
- if (!$this->auth->isSuperAdmin()) {
- $this->error('仅超级管理员可执行');
- }
- $t = time();
- $pid = 0;
- $parent = Db::name('auth_rule')->where('name', 'procuremenroot')->find();
- if ($parent) {
- $pid = (int)$parent['id'];
- } else {
- $pick = Db::name('auth_rule')->where('name', 'procuremen/pick')->find();
- if ($pick) {
- $pid = (int)($pick['pid'] ?? 0);
- }
- }
- if ($pid <= 0) {
- $this->error('未找到协助采购父菜单,请先在权限规则中配置 procuremenroot 或 procuremen/pick');
- }
- $added = 0;
- $menuName = 'purchasecontent/index';
- $menuRule = Db::name('auth_rule')->where('name', $menuName)->find();
- if ($menuRule) {
- $menuId = (int)$menuRule['id'];
- } else {
- $menuId = Db::name('auth_rule')->insertGetId([
- 'type' => 'file',
- 'pid' => $pid,
- 'name' => $menuName,
- 'title' => '通知公告',
- 'icon' => 'fa fa-bullhorn',
- 'url' => '',
- 'ismenu' => 1,
- 'menutype' => 'addtabs',
- 'weigh' => 84,
- 'status' => 'normal',
- 'createtime' => $t,
- 'updatetime' => $t,
- ]);
- $added++;
- }
- foreach (['purchasecontent/add' => '新增', 'purchasecontent/detail' => '查看', 'purchasecontent/del' => '删除', 'purchasecontent/adminselect' => '选择用户'] as $name => $title) {
- if (Db::name('auth_rule')->where('name', $name)->find()) {
- continue;
- }
- Db::name('auth_rule')->insert([
- 'type' => 'file',
- 'pid' => $menuId,
- 'name' => $name,
- 'title' => $title,
- 'icon' => 'fa fa-circle-o',
- 'ismenu' => 0,
- 'status' => 'normal',
- 'createtime' => $t,
- 'updatetime' => $t,
- ]);
- $added++;
- }
- \think\Cache::rm('__menu__');
- $this->success('通知公告菜单安装完成,新增节点 ' . $added . ' 个。请刷新后台并为角色勾选权限。');
- }
- /**
- * @param array<int, mixed> $rows
- */
- protected function enrichContentRows(array &$rows, int $currentAdminId): void
- {
- if ($rows === []) {
- return;
- }
- $contentIds = [];
- $adminIds = [];
- foreach ($rows as $r) {
- if (!is_array($r) && !is_object($r)) {
- continue;
- }
- $arr = is_array($r) ? $r : $r->toArray();
- $cid = (int)($arr['id'] ?? 0);
- if ($cid > 0) {
- $contentIds[$cid] = true;
- }
- foreach (['creator_id', 'sender_id'] as $fk) {
- $aid = (int)($arr[$fk] ?? 0);
- if ($aid > 0) {
- $adminIds[$aid] = true;
- }
- }
- }
- $nameMap = $this->loadAdminNicknameMap(array_keys($adminIds));
- $recvMap = $this->loadRecipientMap(array_keys($contentIds));
- foreach ($rows as &$row) {
- if (is_object($row) && method_exists($row, 'getData')) {
- $data = $row->getData();
- } elseif (is_object($row) && method_exists($row, 'toArray')) {
- $data = $row->toArray();
- } else {
- $data = (array)$row;
- }
- $cid = (int)($data['id'] ?? 0);
- $creatorId = (int)($data['creator_id'] ?? 0);
- $senderId = (int)($data['sender_id'] ?? 0);
- $recv = $recvMap[$cid] ?? ['names' => [], 'count' => 0, 'is_receiver' => false, 'read_time' => null];
- $isSender = ($senderId === $currentAdminId);
- $extra = [
- 'creator_name' => $nameMap[$creatorId] ?? '',
- 'sender_name' => $nameMap[$senderId] ?? '',
- 'sender_id' => $senderId,
- 'recipient_names' => implode('、', $recv['names']),
- 'recipient_count' => $recv['count'],
- 'is_receiver' => $recv['is_receiver'] ? 1 : 0,
- 'is_sender' => $isSender ? 1 : 0,
- 'is_read' => (!empty($recv['read_time'])) ? 1 : 0,
- 'read_time' => $recv['read_time'],
- 'send_time_text' => $this->formatPurchaseContentTime($data['createtime'] ?? ''),
- 'can_delete' => $isSender ? 1 : 0,
- ];
- if (is_object($row)) {
- foreach ($extra as $k => $v) {
- $row->$k = $v;
- }
- } else {
- $row = array_merge($data, $extra);
- }
- }
- unset($row);
- }
- /**
- * @param int[] $adminIds
- * @return array<int, string>
- */
- protected function loadAdminNicknameMap(array $adminIds): array
- {
- $adminIds = array_values(array_unique(array_filter(array_map('intval', $adminIds))));
- if ($adminIds === []) {
- return [];
- }
- $rows = Db::name('admin')
- ->where('id', 'in', $adminIds)
- ->field('id,nickname,username')
- ->select();
- if (!is_array($rows)) {
- return [];
- }
- $out = [];
- foreach ($rows as $r) {
- if (!is_array($r)) {
- continue;
- }
- $id = (int)($r['id'] ?? 0);
- $nick = trim((string)($r['nickname'] ?? ''));
- if ($nick === '') {
- $nick = trim((string)($r['username'] ?? ''));
- }
- $out[$id] = $nick !== '' ? $nick : ('#' . $id);
- }
- return $out;
- }
- /**
- * @param int[] $contentIds
- * @return array<int, array{names: string[], count: int, is_receiver: bool, read_time: int|null}>
- */
- protected function loadRecipientMap(array $contentIds): array
- {
- $contentIds = array_values(array_unique(array_filter(array_map('intval', $contentIds))));
- $out = [];
- if ($contentIds === []) {
- return $out;
- }
- $recvRows = Db::table('purchase_content_recipient')
- ->where('content_id', 'in', $contentIds)
- ->field('content_id,admin_id,read_time')
- ->select();
- if (!is_array($recvRows)) {
- return $out;
- }
- $adminIds = [];
- foreach ($recvRows as $r) {
- if (!is_array($r)) {
- continue;
- }
- $aid = (int)($r['admin_id'] ?? 0);
- if ($aid > 0) {
- $adminIds[$aid] = true;
- }
- }
- $nameMap = $this->loadAdminNicknameMap(array_keys($adminIds));
- $currentAdminId = (int)$this->auth->id;
- foreach ($recvRows as $r) {
- if (!is_array($r)) {
- continue;
- }
- $cid = (int)($r['content_id'] ?? 0);
- $aid = (int)($r['admin_id'] ?? 0);
- if ($cid <= 0) {
- continue;
- }
- if (!isset($out[$cid])) {
- $out[$cid] = ['names' => [], 'count' => 0, 'is_receiver' => false, 'read_time' => null];
- }
- $nm = $nameMap[$aid] ?? ('#' . $aid);
- if ($nm !== '' && !in_array($nm, $out[$cid]['names'], true)) {
- $out[$cid]['names'][] = $nm;
- }
- if ($aid === $currentAdminId) {
- $out[$cid]['is_receiver'] = true;
- $rt = $r['read_time'] ?? null;
- if ($rt !== null && $rt !== '' && stripos((string)$rt, '0000-00-00') !== 0) {
- $out[$cid]['read_time'] = $this->formatPurchaseContentTime($rt);
- }
- }
- }
- foreach ($out as $cid => &$item) {
- sort($item['names'], SORT_STRING);
- $item['count'] = count($item['names']);
- }
- unset($item);
- return $out;
- }
- protected function getContentRowForAdmin(int $id): ?array
- {
- if ($id <= 0) {
- return null;
- }
- $row = $this->model->get($id);
- return $row ? $row->toArray() : null;
- }
- protected function adminExists(int $adminId): bool
- {
- if ($adminId <= 0) {
- return false;
- }
- return (bool)Db::name('admin')->where('id', $adminId)->where('status', 'normal')->count();
- }
- /**
- * 接收人是否属于「供应商证」角色组(id=10)及其子组
- */
- protected function recipientAdminExists(int $adminId): bool
- {
- if ($adminId <= 0 || !$this->adminExists($adminId)) {
- return false;
- }
- $groupIds = $this->loadRecipientAuthGroupIds();
- if ($groupIds === []) {
- return false;
- }
- return (bool)Db::name('auth_group_access')
- ->where('uid', $adminId)
- ->where('group_id', 'in', $groupIds)
- ->count();
- }
- /**
- * auth_group id=10 及其全部子组 id
- *
- * @return int[]
- */
- protected function loadRecipientAuthGroupIds(): array
- {
- static $memo = null;
- if ($memo !== null) {
- return $memo;
- }
- $cacheKey = 'purchase_content_group_ids_' . self::RECIPIENT_AUTH_GROUP_ROOT_ID;
- $cached = Cache::get($cacheKey);
- if (is_array($cached) && $cached !== []) {
- $memo = $cached;
- return $memo;
- }
- $rootId = self::RECIPIENT_AUTH_GROUP_ROOT_ID;
- try {
- $groups = Db::name('auth_group')->where('status', 'normal')->field('id,pid')->select();
- } catch (\Throwable $e) {
- return [$rootId];
- }
- if (!is_array($groups) || $groups === []) {
- return [$rootId];
- }
- $groupList = [];
- foreach ($groups as $g) {
- if (is_array($g)) {
- $groupList[] = $g;
- }
- }
- if ($groupList === []) {
- return [$rootId];
- }
- $tree = \fast\Tree::instance();
- $tree->init($groupList);
- $ids = $tree->getChildrenIds($rootId, true);
- if (!is_array($ids) || $ids === []) {
- $memo = [$rootId];
- return $memo;
- }
- $memo = array_values(array_unique(array_filter(array_map('intval', $ids))));
- Cache::set($cacheKey, $memo, self::RECIPIENT_LIST_CACHE_TTL);
- return $memo;
- }
- /**
- * 新增公告:可选接收人列表(仅角色组 id=10 及其子组下的用户)
- *
- * @return array<int, array{id:int, username:string, nickname:string, label:string}>
- */
- protected function loadNormalAdminList(): array
- {
- $cacheKey = 'purchase_content_admin_list_v2_' . self::RECIPIENT_AUTH_GROUP_ROOT_ID;
- $cached = Cache::get($cacheKey);
- if (is_array($cached)) {
- return $cached;
- }
- $groupIds = $this->loadRecipientAuthGroupIds();
- if ($groupIds === []) {
- return [];
- }
- try {
- $adminIds = Db::name('auth_group_access')
- ->where('group_id', 'in', $groupIds)
- ->column('uid');
- } catch (\Throwable $e) {
- $adminIds = [];
- }
- $adminIds = is_array($adminIds)
- ? array_values(array_unique(array_filter(array_map('intval', $adminIds))))
- : [];
- if ($adminIds === []) {
- return [];
- }
- try {
- $rows = Db::name('admin')
- ->where('status', 'normal')
- ->where('id', 'in', $adminIds)
- ->field('id,username,nickname')
- ->order('id', 'asc')
- ->select();
- } catch (\Throwable $e) {
- $rows = [];
- }
- if (!is_array($rows)) {
- return [];
- }
- $out = [];
- foreach ($rows as $r) {
- if (!is_array($r)) {
- continue;
- }
- $id = (int)($r['id'] ?? 0);
- if ($id <= 0) {
- continue;
- }
- $username = trim((string)($r['username'] ?? ''));
- $nickname = trim((string)($r['nickname'] ?? ''));
- if ($nickname === '') {
- $nickname = $username;
- }
- if ($nickname === '') {
- $nickname = '#' . $id;
- }
- $out[] = [
- 'id' => $id,
- 'username' => $username,
- 'nickname' => $nickname,
- 'label' => $nickname,
- ];
- }
- Cache::set($cacheKey, $out, self::RECIPIENT_LIST_CACHE_TTL);
- return $out;
- }
- /**
- * @param mixed $raw
- * @return int[]
- */
- protected function parseIdList($raw): array
- {
- if (is_array($raw)) {
- $parts = $raw;
- } else {
- $parts = preg_split('/\s*,\s*/', trim((string)$raw), -1, PREG_SPLIT_NO_EMPTY);
- }
- if (!is_array($parts)) {
- return [];
- }
- $out = [];
- foreach ($parts as $p) {
- $id = (int)$p;
- if ($id > 0) {
- $out[$id] = $id;
- }
- }
- return array_values($out);
- }
- /**
- * 解析并校验接收人 id(须为角色组 id=10 及其子组下的正常用户)
- *
- * @param mixed $raw
- * @return int[]
- */
- protected function parseRecipientIdList($raw): array
- {
- $out = [];
- foreach ($this->parseIdList($raw) as $id) {
- if ($this->recipientAdminExists($id)) {
- $out[$id] = $id;
- }
- }
- return array_values($out);
- }
- }
|