diff --git a/saiadmin-artd/src/locales/langs/en/dice/ante_config.json b/saiadmin-artd/src/locales/langs/en/dice/ante_config.json
new file mode 100644
index 0000000..2130a3c
--- /dev/null
+++ b/saiadmin-artd/src/locales/langs/en/dice/ante_config.json
@@ -0,0 +1,37 @@
+{
+ "search": {
+ "name": "Name",
+ "title": "Title",
+ "isDefault": "Default",
+ "placeholderName": "Please enter name",
+ "placeholderTitle": "Please enter title",
+ "placeholderIsDefault": "Please select default status"
+ },
+ "table": {
+ "id": "ID",
+ "name": "Name",
+ "title": "Title",
+ "mult": "Ante Multiplier",
+ "isDefault": "Default Ante",
+ "defaultYes": "Yes",
+ "defaultNo": "No",
+ "createTime": "Create Time",
+ "updateTime": "Update Time"
+ },
+ "form": {
+ "titleAdd": "Add Ante Config",
+ "titleEdit": "Edit Ante Config",
+ "labelName": "Name",
+ "labelTitle": "Title",
+ "labelMult": "Ante Multiplier",
+ "labelIsDefault": "Default Ante",
+ "placeholderName": "Please enter name",
+ "placeholderTitle": "Please enter title",
+ "ruleNameRequired": "Please enter name",
+ "ruleTitleRequired": "Please enter title",
+ "ruleMultRequired": "Please enter ante multiplier",
+ "ruleDefaultRequired": "Please select default status",
+ "addSuccess": "Added successfully",
+ "editSuccess": "Updated successfully"
+ }
+}
diff --git a/saiadmin-artd/src/locales/langs/zh/dice/ante_config.json b/saiadmin-artd/src/locales/langs/zh/dice/ante_config.json
new file mode 100644
index 0000000..4d33405
--- /dev/null
+++ b/saiadmin-artd/src/locales/langs/zh/dice/ante_config.json
@@ -0,0 +1,37 @@
+{
+ "search": {
+ "name": "名称",
+ "title": "标题",
+ "isDefault": "是否默认",
+ "placeholderName": "请输入名称",
+ "placeholderTitle": "请输入标题",
+ "placeholderIsDefault": "请选择是否默认"
+ },
+ "table": {
+ "id": "ID",
+ "name": "名称",
+ "title": "标题",
+ "mult": "底注倍率",
+ "isDefault": "默认底注",
+ "defaultYes": "是",
+ "defaultNo": "否",
+ "createTime": "创建时间",
+ "updateTime": "更新时间"
+ },
+ "form": {
+ "titleAdd": "新增底注配置",
+ "titleEdit": "编辑底注配置",
+ "labelName": "名称",
+ "labelTitle": "标题",
+ "labelMult": "底注倍率",
+ "labelIsDefault": "默认底注",
+ "placeholderName": "请输入名称",
+ "placeholderTitle": "请输入标题",
+ "ruleNameRequired": "请输入名称",
+ "ruleTitleRequired": "请输入标题",
+ "ruleMultRequired": "请输入底注倍率",
+ "ruleDefaultRequired": "请选择是否默认底注",
+ "addSuccess": "新增成功",
+ "editSuccess": "修改成功"
+ }
+}
diff --git a/saiadmin-artd/src/views/plugin/dice/ante_config/index/index.vue b/saiadmin-artd/src/views/plugin/dice/ante_config/index/index.vue
new file mode 100644
index 0000000..4da7ac2
--- /dev/null
+++ b/saiadmin-artd/src/views/plugin/dice/ante_config/index/index.vue
@@ -0,0 +1,139 @@
+
+
+
+
+
+
+
+
+
+
+
+
+ {{ $t('table.actions.add') }}
+
+
+
+
+
+ {{ $t('table.actions.delete') }}
+
+
+
+
+
+
+
+
+ {{ row.is_default === 1 ? $t('page.table.defaultYes') : $t('page.table.defaultNo') }}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/saiadmin-artd/src/views/plugin/dice/ante_config/index/modules/edit-dialog.vue b/saiadmin-artd/src/views/plugin/dice/ante_config/index/modules/edit-dialog.vue
new file mode 100644
index 0000000..1c1b738
--- /dev/null
+++ b/saiadmin-artd/src/views/plugin/dice/ante_config/index/modules/edit-dialog.vue
@@ -0,0 +1,126 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {{ $t('page.table.defaultYes') }}
+ {{ $t('page.table.defaultNo') }}
+
+
+
+
+ {{ $t('common.cancel') }}
+ {{ $t('table.form.submit') }}
+
+
+
+
+
diff --git a/saiadmin-artd/src/views/plugin/dice/ante_config/index/modules/table-search.vue b/saiadmin-artd/src/views/plugin/dice/ante_config/index/modules/table-search.vue
new file mode 100644
index 0000000..17a5d81
--- /dev/null
+++ b/saiadmin-artd/src/views/plugin/dice/ante_config/index/modules/table-search.vue
@@ -0,0 +1,68 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/saiadmin-artd/src/views/plugin/dice/api/ante_config/index.ts b/saiadmin-artd/src/views/plugin/dice/api/ante_config/index.ts
new file mode 100644
index 0000000..ab6fd1b
--- /dev/null
+++ b/saiadmin-artd/src/views/plugin/dice/api/ante_config/index.ts
@@ -0,0 +1,40 @@
+import request from '@/utils/http'
+
+/**
+ * 底注配置 API
+ */
+export default {
+ list(params: Record) {
+ return request.get({
+ url: '/core/dice/ante_config/DiceAnteConfig/index',
+ params
+ })
+ },
+
+ read(id: number | string) {
+ return request.get({
+ url: '/core/dice/ante_config/DiceAnteConfig/read?id=' + id
+ })
+ },
+
+ save(params: Record) {
+ return request.post({
+ url: '/core/dice/ante_config/DiceAnteConfig/save',
+ data: params
+ })
+ },
+
+ update(params: Record) {
+ return request.put({
+ url: '/core/dice/ante_config/DiceAnteConfig/update',
+ data: params
+ })
+ },
+
+ delete(params: Record) {
+ return request.del({
+ url: '/core/dice/ante_config/DiceAnteConfig/destroy',
+ data: params
+ })
+ }
+}
diff --git a/server/app/dice/controller/ante_config/DiceAnteConfigController.php b/server/app/dice/controller/ante_config/DiceAnteConfigController.php
new file mode 100644
index 0000000..6207181
--- /dev/null
+++ b/server/app/dice/controller/ante_config/DiceAnteConfigController.php
@@ -0,0 +1,78 @@
+logic = new DiceAnteConfigLogic();
+ $this->validate = new DiceAnteConfigValidate();
+ parent::__construct();
+ }
+
+ #[Permission('底注配置列表', 'dice:ante_config:index:index')]
+ public function index(Request $request): Response
+ {
+ $where = $request->more([
+ ['name', ''],
+ ['title', ''],
+ ['is_default', ''],
+ ]);
+ $query = $this->logic->search($where);
+ $data = $this->logic->getList($query);
+ return $this->success($data);
+ }
+
+ #[Permission('底注配置读取', 'dice:ante_config:index:read')]
+ public function read(Request $request): Response
+ {
+ $id = $request->input('id', '');
+ $model = $this->logic->read($id);
+ $data = is_array($model) ? $model : $model->toArray();
+ return $this->success($data);
+ }
+
+ #[Permission('底注配置添加', 'dice:ante_config:index:save')]
+ public function save(Request $request): Response
+ {
+ $data = $request->post();
+ $this->validate('save', $data);
+ $result = $this->logic->add($data);
+ return $result ? $this->success('add success') : $this->fail('add failed');
+ }
+
+ #[Permission('底注配置修改', 'dice:ante_config:index:update')]
+ public function update(Request $request): Response
+ {
+ $data = $request->post();
+ $this->validate('update', $data);
+ $result = $this->logic->edit($data['id'], $data);
+ return $result ? $this->success('update success') : $this->fail('update failed');
+ }
+
+ #[Permission('底注配置删除', 'dice:ante_config:index:destroy')]
+ public function destroy(Request $request): Response
+ {
+ $ids = $request->post('ids', '');
+ if (empty($ids)) {
+ return $this->fail('please select data to delete');
+ }
+ $result = $this->logic->destroy($ids);
+ return $result ? $this->success('delete success') : $this->fail('delete failed');
+ }
+}
diff --git a/server/app/dice/logic/ante_config/DiceAnteConfigLogic.php b/server/app/dice/logic/ante_config/DiceAnteConfigLogic.php
new file mode 100644
index 0000000..27d1283
--- /dev/null
+++ b/server/app/dice/logic/ante_config/DiceAnteConfigLogic.php
@@ -0,0 +1,90 @@
+model = new DiceAnteConfig();
+ }
+
+ public function add(array $data): mixed
+ {
+ return $this->transaction(function () use ($data) {
+ $this->normalizeDefaultField($data);
+ if ((int) ($data['is_default'] ?? 0) === 1) {
+ $this->clearOtherDefaults();
+ }
+ return parent::add($data);
+ });
+ }
+
+ public function edit($id, array $data): mixed
+ {
+ return $this->transaction(function () use ($id, $data) {
+ $this->normalizeDefaultField($data);
+ if ((int) ($data['is_default'] ?? 0) === 1) {
+ $this->clearOtherDefaults((int) $id);
+ }
+ return parent::edit($id, $data);
+ });
+ }
+
+ /**
+ * 防止删除后全表无默认:若删除了默认项,自动把最小 id 设为默认。
+ */
+ public function destroy($ids): bool
+ {
+ return $this->transaction(function () use ($ids) {
+ $idList = is_array($ids) ? $ids : explode(',', (string) $ids);
+ $intIds = [];
+ foreach ($idList as $v) {
+ $iv = (int) $v;
+ if ($iv > 0) {
+ $intIds[] = $iv;
+ }
+ }
+ if ($intIds === []) {
+ return false;
+ }
+
+ $deletedDefaultCount = $this->model->whereIn('id', $intIds)->where('is_default', 1)->count();
+ $result = $this->model->destroy($intIds);
+ if ($result && $deletedDefaultCount > 0) {
+ $first = $this->model->order('id', 'asc')->find();
+ if ($first) {
+ $this->model->where('id', (int) $first['id'])->update(['is_default' => 1]);
+ }
+ }
+ return (bool) $result;
+ });
+ }
+
+ private function normalizeDefaultField(array &$data): void
+ {
+ if (!array_key_exists('is_default', $data)) {
+ return;
+ }
+ $data['is_default'] = ((int) $data['is_default']) === 1 ? 1 : 0;
+ }
+
+ private function clearOtherDefaults(?int $excludeId = null): void
+ {
+ $query = $this->model->where('is_default', 1);
+ if ($excludeId !== null && $excludeId > 0) {
+ $query->where('id', '<>', $excludeId);
+ }
+ $query->update(['is_default' => 0]);
+ }
+}
diff --git a/server/app/dice/model/ante_config/DiceAnteConfig.php b/server/app/dice/model/ante_config/DiceAnteConfig.php
new file mode 100644
index 0000000..6d46477
--- /dev/null
+++ b/server/app/dice/model/ante_config/DiceAnteConfig.php
@@ -0,0 +1,48 @@
+where('name', 'like', '%' . $value . '%');
+ }
+ }
+
+ public function searchTitleAttr($query, $value): void
+ {
+ if ($value !== '' && $value !== null) {
+ $query->where('title', 'like', '%' . $value . '%');
+ }
+ }
+
+ public function searchIsDefaultAttr($query, $value): void
+ {
+ if ($value !== '' && $value !== null) {
+ $query->where('is_default', (int) $value);
+ }
+ }
+}
diff --git a/server/app/dice/validate/ante_config/DiceAnteConfigValidate.php b/server/app/dice/validate/ante_config/DiceAnteConfigValidate.php
new file mode 100644
index 0000000..d081829
--- /dev/null
+++ b/server/app/dice/validate/ante_config/DiceAnteConfigValidate.php
@@ -0,0 +1,34 @@
+ 'require|max:64',
+ 'title' => 'require|max:255',
+ 'is_default' => 'require|in:0,1',
+ 'mult' => 'require|integer|gt:0',
+ ];
+
+ protected $message = [
+ 'name' => '名称必须填写',
+ 'title' => '标题必须填写',
+ 'is_default' => '默认底注标记必须为 0 或 1',
+ 'mult' => '底注倍率必须为大于 0 的整数',
+ ];
+
+ protected $scene = [
+ 'save' => ['name', 'title', 'is_default', 'mult'],
+ 'update' => ['name', 'title', 'is_default', 'mult'],
+ ];
+}
diff --git a/server/db/dice_ante_config.sql b/server/db/dice_ante_config.sql
new file mode 100644
index 0000000..a2e5977
--- /dev/null
+++ b/server/db/dice_ante_config.sql
@@ -0,0 +1,17 @@
+-- 底注配置表
+CREATE TABLE IF NOT EXISTS `dice_ante_config` (
+ `id` int unsigned NOT NULL AUTO_INCREMENT COMMENT '主键ID',
+ `name` varchar(64) NOT NULL COMMENT '名称',
+ `title` varchar(255) NOT NULL COMMENT '标题',
+ `is_default` tinyint(1) NOT NULL DEFAULT 0 COMMENT '是否默认底注:0否 1是(全表只允许一条)',
+ `mult` int NOT NULL DEFAULT 1 COMMENT '底注倍率',
+ `create_time` datetime DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
+ `update_time` datetime DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
+ PRIMARY KEY (`id`),
+ KEY `idx_is_default` (`is_default`)
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='Dice 底注配置表';
+
+-- 可选初始化数据(保留一条默认底注)
+INSERT INTO `dice_ante_config` (`name`, `title`, `is_default`, `mult`)
+SELECT 'default', '默认底注', 1, 1
+WHERE NOT EXISTS (SELECT 1 FROM `dice_ante_config` LIMIT 1);
diff --git a/server/db/dice_ante_config_menu.sql b/server/db/dice_ante_config_menu.sql
new file mode 100644
index 0000000..e95ecb6
--- /dev/null
+++ b/server/db/dice_ante_config_menu.sql
@@ -0,0 +1,62 @@
+-- 底注配置菜单与权限
+-- 说明:默认挂载在「大富翁」目录(path=/dice)下;若不存在则自动创建目录。
+
+SET @now = NOW();
+
+-- 1) 找到或创建 Dice 顶级目录
+SET @dice_root_id = (
+ SELECT `id` FROM `sa_system_menu`
+ WHERE `path` = '/dice' AND `type` = 1
+ ORDER BY `id` ASC LIMIT 1
+);
+
+INSERT INTO `sa_system_menu`
+(`parent_id`,`name`,`code`,`slug`,`type`,`path`,`component`,`method`,`icon`,`sort`,`is_iframe`,`is_keep_alive`,`is_hidden`,`is_fixed_tab`,`is_full_page`,`generate_id`,`generate_key`,`status`,`create_time`,`update_time`)
+SELECT 0, '大富翁', 'Dice', NULL, 1, '/dice', NULL, NULL, 'ri:gamepad-line', 100, 2, 2, 2, 2, 2, 0, NULL, 1, @now, @now
+WHERE @dice_root_id IS NULL;
+
+SET @dice_root_id = (
+ SELECT `id` FROM `sa_system_menu`
+ WHERE `path` = '/dice' AND `type` = 1
+ ORDER BY `id` ASC LIMIT 1
+);
+
+-- 2) 创建底注配置菜单
+INSERT INTO `sa_system_menu`
+(`parent_id`,`name`,`code`,`slug`,`type`,`path`,`component`,`method`,`icon`,`sort`,`is_iframe`,`is_keep_alive`,`is_hidden`,`is_fixed_tab`,`is_full_page`,`generate_id`,`generate_key`,`status`,`create_time`,`update_time`)
+SELECT @dice_root_id, '底注配置', 'AnteConfig', NULL, 2, 'ante_config', '/dice/ante_config/index', NULL, 'ri:coins-line', 92, 2, 2, 2, 2, 2, 0, NULL, 1, @now, @now
+WHERE NOT EXISTS (
+ SELECT 1 FROM `sa_system_menu` WHERE `path` = 'ante_config' AND `component` = '/dice/ante_config/index' AND `type` = 2
+);
+
+SET @ante_menu_id = (
+ SELECT `id` FROM `sa_system_menu`
+ WHERE `path` = 'ante_config' AND `component` = '/dice/ante_config/index' AND `type` = 2
+ ORDER BY `id` ASC LIMIT 1
+);
+
+-- 3) 创建按钮权限
+INSERT INTO `sa_system_menu`
+(`parent_id`,`name`,`code`,`slug`,`type`,`path`,`component`,`method`,`sort`,`is_iframe`,`is_keep_alive`,`is_hidden`,`is_fixed_tab`,`is_full_page`,`generate_id`,`generate_key`,`status`,`create_time`,`update_time`)
+SELECT @ante_menu_id, '数据列表', '', 'dice:ante_config:index:index', 3, '', '', '', 100, 2, 2, 2, 2, 2, 0, NULL, 1, @now, @now
+WHERE NOT EXISTS (SELECT 1 FROM `sa_system_menu` WHERE `slug` = 'dice:ante_config:index:index' AND `type` = 3);
+
+INSERT INTO `sa_system_menu`
+(`parent_id`,`name`,`code`,`slug`,`type`,`path`,`component`,`method`,`sort`,`is_iframe`,`is_keep_alive`,`is_hidden`,`is_fixed_tab`,`is_full_page`,`generate_id`,`generate_key`,`status`,`create_time`,`update_time`)
+SELECT @ante_menu_id, '读取', '', 'dice:ante_config:index:read', 3, '', '', '', 100, 2, 2, 2, 2, 2, 0, NULL, 1, @now, @now
+WHERE NOT EXISTS (SELECT 1 FROM `sa_system_menu` WHERE `slug` = 'dice:ante_config:index:read' AND `type` = 3);
+
+INSERT INTO `sa_system_menu`
+(`parent_id`,`name`,`code`,`slug`,`type`,`path`,`component`,`method`,`sort`,`is_iframe`,`is_keep_alive`,`is_hidden`,`is_fixed_tab`,`is_full_page`,`generate_id`,`generate_key`,`status`,`create_time`,`update_time`)
+SELECT @ante_menu_id, '添加', '', 'dice:ante_config:index:save', 3, '', '', '', 100, 2, 2, 2, 2, 2, 0, NULL, 1, @now, @now
+WHERE NOT EXISTS (SELECT 1 FROM `sa_system_menu` WHERE `slug` = 'dice:ante_config:index:save' AND `type` = 3);
+
+INSERT INTO `sa_system_menu`
+(`parent_id`,`name`,`code`,`slug`,`type`,`path`,`component`,`method`,`sort`,`is_iframe`,`is_keep_alive`,`is_hidden`,`is_fixed_tab`,`is_full_page`,`generate_id`,`generate_key`,`status`,`create_time`,`update_time`)
+SELECT @ante_menu_id, '修改', '', 'dice:ante_config:index:update', 3, '', '', '', 100, 2, 2, 2, 2, 2, 0, NULL, 1, @now, @now
+WHERE NOT EXISTS (SELECT 1 FROM `sa_system_menu` WHERE `slug` = 'dice:ante_config:index:update' AND `type` = 3);
+
+INSERT INTO `sa_system_menu`
+(`parent_id`,`name`,`code`,`slug`,`type`,`path`,`component`,`method`,`sort`,`is_iframe`,`is_keep_alive`,`is_hidden`,`is_fixed_tab`,`is_full_page`,`generate_id`,`generate_key`,`status`,`create_time`,`update_time`)
+SELECT @ante_menu_id, '删除', '', 'dice:ante_config:index:destroy', 3, '', '', '', 100, 2, 2, 2, 2, 2, 0, NULL, 1, @now, @now
+WHERE NOT EXISTS (SELECT 1 FROM `sa_system_menu` WHERE `slug` = 'dice:ante_config:index:destroy' AND `type` = 3);
diff --git a/server/plugin/saiadmin/config/route.php b/server/plugin/saiadmin/config/route.php
index 8dee7a0..2fbe077 100644
--- a/server/plugin/saiadmin/config/route.php
+++ b/server/plugin/saiadmin/config/route.php
@@ -118,6 +118,7 @@ Route::group('/core', function () {
Route::post('/dice/reward_config/DiceRewardConfig/batchUpdate', [\app\dice\controller\reward_config\DiceRewardConfigController::class, 'batchUpdate']);
Route::post('/dice/reward_config/DiceRewardConfig/createRewardReference', [\app\dice\controller\reward_config\DiceRewardConfigController::class, 'createRewardReference']);
Route::post('/dice/reward_config/DiceRewardConfig/runWeightTest', [\app\dice\controller\reward_config\DiceRewardConfigController::class, 'runWeightTest']);
+ fastRoute('dice/ante_config/DiceAnteConfig', \app\dice\controller\ante_config\DiceAnteConfigController::class);
fastRoute('dice/lottery_pool_config/DiceLotteryPoolConfig', \app\dice\controller\lottery_pool_config\DiceLotteryPoolConfigController::class);
Route::get('/dice/lottery_pool_config/DiceLotteryPoolConfig/getOptions', [\app\dice\controller\lottery_pool_config\DiceLotteryPoolConfigController::class, 'getOptions']);
Route::get('/dice/lottery_pool_config/DiceLotteryPoolConfig/getCurrentPool', [\app\dice\controller\lottery_pool_config\DiceLotteryPoolConfigController::class, 'getCurrentPool']);