Ver Fonte

Merge branch 'saas_adminUi' of http://1.14.104.71:10880/txl/ylrz_saas_his_scrm_adminUI into saas_adminUi

lmx há 22 horas atrás
pai
commit
d4b402778b

+ 14 - 24
src/api/his/redPacketConfig.js

@@ -3,26 +3,16 @@ import request from '@/utils/request'
 // 查询多商户配置列表
 // 查询多商户配置列表
 export function listMore(query) {
 export function listMore(query) {
   return request({
   return request({
-    url: '/store/redPacket/more/list',
+    url: '/redPacket/more/list',
     method: 'get',
     method: 'get',
     params: query
     params: query
   })
   })
 }
 }
 
 
-
-export function getRedPacketMchId(query) {
-  return request({
-    url: '/store/redPacket/more/getRedPacketConfig',
-    method: 'get',
-    params: query
-  })
-}
-
-
 // 查询多商户配置详细
 // 查询多商户配置详细
 export function getMore(id) {
 export function getMore(id) {
   return request({
   return request({
-    url: '/store/redPacket/more/' + id,
+    url: '/redPacket/more/' + id,
     method: 'get'
     method: 'get'
   })
   })
 }
 }
@@ -30,7 +20,7 @@ export function getMore(id) {
 // 新增多商户配置
 // 新增多商户配置
 export function addMore(data) {
 export function addMore(data) {
   return request({
   return request({
-    url: '/store/redPacket/more',
+    url: '/redPacket/more',
     method: 'post',
     method: 'post',
     data: data
     data: data
   })
   })
@@ -39,24 +29,16 @@ export function addMore(data) {
 // 修改多商户配置
 // 修改多商户配置
 export function updateMore(data) {
 export function updateMore(data) {
   return request({
   return request({
-    url: '/store/redPacket/more',
+    url: '/redPacket/more',
     method: 'put',
     method: 'put',
     data: data
     data: data
   })
   })
 }
 }
 
 
-export function updateChangeMchId(data) {
-  return request({
-    url: '/store/redPacket/more/updateChangeMchId',
-    method: 'post',
-    data: data
-  })
-}
-
 // 删除多商户配置
 // 删除多商户配置
 export function delMore(id) {
 export function delMore(id) {
   return request({
   return request({
-    url: '/store/redPacket/more/' + id,
+    url: '/redPacket/more/' + id,
     method: 'delete'
     method: 'delete'
   })
   })
 }
 }
@@ -64,8 +46,16 @@ export function delMore(id) {
 // 导出多商户配置
 // 导出多商户配置
 export function exportMore(query) {
 export function exportMore(query) {
   return request({
   return request({
-    url: '/store/redPacket/more/export',
+    url: '/redPacket/more/export',
     method: 'get',
     method: 'get',
     params: query
     params: query
   })
   })
 }
 }
+
+// 获取租户列表
+export function getTenantList() {
+  return request({
+    url: '/redPacket/more/tenantList',
+    method: 'get'
+  })
+}

+ 0 - 18
src/api/monitor/taskRegistry.js

@@ -1,18 +0,0 @@
-import request from '@/utils/request'
-
-// Bean registry list (paginated)
-export function listTaskRegistry(query) {
-  return request({
-    url: '/monitor/taskRegistry/list',
-    method: 'get',
-    params: query
-  })
-}
-
-// Refresh Bean registry cache
-export function refreshTaskRegistry() {
-  return request({
-    url: '/monitor/taskRegistry/refresh',
-    method: 'post'
-  })
-}

+ 8 - 0
src/api/monitor/tenantJob.js

@@ -44,6 +44,14 @@ export function syncAllTenantJob() {
   })
   })
 }
 }
 
 
+export function listTenantJobConfig(query) {
+  return request({
+    url: '/monitor/tenantJob/config/list',
+    method: 'get',
+    params: query
+  })
+}
+
 export function updateTenantJobStatus(configId, status) {
 export function updateTenantJobStatus(configId, status) {
   return request({
   return request({
     url: '/monitor/tenantJob/config/status',
     url: '/monitor/tenantJob/config/status',

+ 46 - 91
src/views/his/redPacketConfig/index.vue

@@ -68,25 +68,6 @@
           v-hasPermi="['redPacket:more:remove']"
           v-hasPermi="['redPacket:more:remove']"
         >删除</el-button>
         >删除</el-button>
       </el-col>
       </el-col>
-      <el-col :span="1.5">
-        <el-tag
-          type="primary"
-          size="large"
-          style="font-size: 16px;"
-        >
-          当前使用的商户号:{{this.redPacketMchId}}
-        </el-tag>
-      </el-col>
-      <el-col :span="1.5">
-        <el-button
-          type="success"
-          plain
-          icon="el-icon-edit"
-          size="small"
-          @click="handleEditRedPacket"
-          v-hasPermi="['redPacket:more:editRedPacket']"
-        >修改当前发送的红包的商户号</el-button>
-      </el-col>
       <right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar>
       <right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar>
     </el-row>
     </el-row>
 
 
@@ -110,6 +91,12 @@
       <el-table-column label="pub_key.pem证书" align="center" prop="publicKeyPath" />
       <el-table-column label="pub_key.pem证书" align="center" prop="publicKeyPath" />
       <el-table-column label="回调地址" align="center" prop="notifyUrl" />
       <el-table-column label="回调地址" align="center" prop="notifyUrl" />
       <el-table-column label="回调地址" align="center" prop="notifyUrlScrm" />
       <el-table-column label="回调地址" align="center" prop="notifyUrlScrm" />
+      <el-table-column label="分配租户" align="center" prop="tenantName" :show-overflow-tooltip="true">
+        <template slot-scope="scope">
+          <el-tag v-if="scope.row.tenantId" type="success" size="small">{{ scope.row.tenantName || scope.row.tenantId }}</el-tag>
+          <el-tag v-else type="info" size="small">未分配</el-tag>
+        </template>
+      </el-table-column>
       <el-table-column label="操作" align="center" class-name="small-padding fixed-width">
       <el-table-column label="操作" align="center" class-name="small-padding fixed-width">
         <template slot-scope="scope">
         <template slot-scope="scope">
           <el-button
           <el-button
@@ -183,31 +170,24 @@
         <el-form-item label="回调地址" prop="notifyUrlScrm">
         <el-form-item label="回调地址" prop="notifyUrlScrm">
           <el-input v-model="form.notifyUrlScrm" placeholder="请输入回调地址notifyUrlScrm" />
           <el-input v-model="form.notifyUrlScrm" placeholder="请输入回调地址notifyUrlScrm" />
         </el-form-item>
         </el-form-item>
-      </el-form>
-      <div slot="footer" class="dialog-footer">
-        <el-button type="primary" @click="submitForm">确 定</el-button>
-        <el-button @click="cancel">取 消</el-button>
-      </div>
-    </el-dialog>
-
-    <el-dialog :title="redPacketOpen.title" :visible.sync="redPacketOpen.open" width="600px" append-to-body>
-      <el-form ref="redPacketOpen" :model="redPacketOpen" label-width="110px">
-        <el-form-item label="商户号" prop="cateId">
-          <el-select v-model="redPacketOpen.newChangeMchId" placeholder="请选择" clearable size="small">
+        <el-form-item label="分配租户" prop="tenantId">
+          <el-select v-model="form.tenantId" placeholder="请选择要分配的租户(同步到租户库)" clearable style="width: 100%;">
             <el-option
             <el-option
-              v-for="dict in moreList"
-              :key="dict.mchId"
-              :label="dict.mchId"
-              :value="dict.mchId"
+              v-for="item in tenantList"
+              :key="item.id"
+              :label="item.tenantName + ' (' + item.tenantCode + ')'"
+              :value="item.id"
             />
             />
           </el-select>
           </el-select>
+          <div class="form-tip">选择租户后,该商户配置将同步到指定租户的数据库中</div>
         </el-form-item>
         </el-form-item>
       </el-form>
       </el-form>
       <div slot="footer" class="dialog-footer">
       <div slot="footer" class="dialog-footer">
-        <el-button type="primary" @click="submitFormChangeMchId">确 定</el-button>
-        <el-button @click="cancelChangeMchId">取 消</el-button>
+        <el-button type="primary" @click="submitForm">确 定</el-button>
+        <el-button @click="cancel">取 消</el-button>
       </div>
       </div>
     </el-dialog>
     </el-dialog>
+
   </div>
   </div>
 </template>
 </template>
 
 
@@ -218,8 +198,7 @@ import {
   delMore,
   delMore,
   addMore,
   addMore,
   updateMore,
   updateMore,
-  getRedPacketMchId,
-  updateChangeMchId
+  getTenantList
 } from '@/api/his/redPacketConfig'
 } from '@/api/his/redPacketConfig'
 
 
 export default {
 export default {
@@ -240,15 +219,10 @@ export default {
       showSearch: true,
       showSearch: true,
       // 总条数
       // 总条数
       total: 0,
       total: 0,
-      redPacketMchId: null,
-      redPacketOpen:{
-        open:false,
-        title:null,
-        oldChangeMchId:null,
-        newChangeMchId:null,
-      },
       // 多商户配置表格数据
       // 多商户配置表格数据
       moreList: [],
       moreList: [],
+      // 租户列表
+      tenantList: [],
       // 弹出层标题
       // 弹出层标题
       title: "",
       title: "",
       // 是否显示弹出层
       // 是否显示弹出层
@@ -275,13 +249,11 @@ export default {
       form: {},
       form: {},
       // 表单校验
       // 表单校验
       rules: {},
       rules: {},
-      redPacketOpenRule:{
-        newChangeMchId:[{ required: true, trigger: "blur", message: "商户号不能为空" }]
-      },
     };
     };
   },
   },
   created() {
   created() {
     this.getList();
     this.getList();
+    this.loadTenantList();
   },
   },
   methods: {
   methods: {
     /** 查询多商户配置列表 */
     /** 查询多商户配置列表 */
@@ -293,21 +265,12 @@ export default {
         this.total = response.total;
         this.total = response.total;
         this.loading = false;
         this.loading = false;
       });
       });
-      getRedPacketMchId().then(res=>{
-        this.redPacketMchId=res.data
-      })
     },
     },
     // 取消按钮
     // 取消按钮
     cancel() {
     cancel() {
       this.open = false;
       this.open = false;
       this.reset();
       this.reset();
     },
     },
-    cancelChangeMchId() {
-      this.redPacketOpen.open=false;
-      this.redPacketOpen.title=false;
-      this.redPacketOpen.oldChangeMchId=false;
-      this.redPacketOpen.newChangeMchId=false;
-    },
     // 表单重置
     // 表单重置
     reset() {
     reset() {
       this.form = {
       this.form = {
@@ -324,10 +287,17 @@ export default {
         publicKeyId: null,
         publicKeyId: null,
         publicKeyPath: null,
         publicKeyPath: null,
         notifyUrl: null,
         notifyUrl: null,
-        notifyUrlScrm: null
+        notifyUrlScrm: null,
+        tenantId: null
       };
       };
       this.resetForm("form");
       this.resetForm("form");
     },
     },
+    // 加载租户列表
+    loadTenantList() {
+      getTenantList().then(res => {
+        this.tenantList = res.data || [];
+      });
+    },
     /** 搜索按钮操作 */
     /** 搜索按钮操作 */
     handleQuery() {
     handleQuery() {
       this.queryParams.pageNum = 1;
       this.queryParams.pageNum = 1;
@@ -360,11 +330,6 @@ export default {
         this.title = "修改多商户配置";
         this.title = "修改多商户配置";
       });
       });
     },
     },
-    handleEditRedPacket(){
-      this.redPacketOpen.open= true;
-      this.redPacketOpen.title="修改发送红包的商户号";
-
-    },
     /** 提交按钮 */
     /** 提交按钮 */
     submitForm() {
     submitForm() {
       this.$refs["form"].validate(valid => {
       this.$refs["form"].validate(valid => {
@@ -385,39 +350,29 @@ export default {
         }
         }
       });
       });
     },
     },
-
-    /** 提交修改发送红包的商户号- */
-    submitFormChangeMchId() {
-      this.$refs["redPacketOpen"].validate(valid => {
-        if (valid) {
-            this.redPacketOpen.oldChangeMchId=this.redPacketMchId;
-            if (this.redPacketOpen.newChangeMchId==null){
-              return this.$message.error("修改的商户号不能为空")
-            }
-
-            updateChangeMchId(this.redPacketOpen).then(response => {
-              this.msgSuccess("修改成功");
-              this.cancelChangeMchId();
-              this.getList();
-            });
-
-        }
-      });
-    },
     /** 删除按钮操作 */
     /** 删除按钮操作 */
     handleDelete(row) {
     handleDelete(row) {
       const ids = row.id || this.ids;
       const ids = row.id || this.ids;
       this.$confirm('是否确认删除多商户配置编号为"' + ids + '"的数据项?', "警告", {
       this.$confirm('是否确认删除多商户配置编号为"' + ids + '"的数据项?', "警告", {
-          confirmButtonText: "确定",
-          cancelButtonText: "取消",
-          type: "warning"
-        }).then(function() {
-          return delMore(ids);
-        }).then(() => {
-          this.getList();
-          this.msgSuccess("删除成功");
-        }).catch(() => {});
+        confirmButtonText: "确定",
+        cancelButtonText: "取消",
+        type: "warning"
+      }).then(function() {
+        return delMore(ids);
+      }).then(() => {
+        this.getList();
+        this.msgSuccess("删除成功");
+      }).catch(() => {});
     },
     },
   }
   }
 };
 };
 </script>
 </script>
+
+<style scoped>
+.form-tip {
+  font-size: 12px;
+  color: #909399;
+  margin-top: 5px;
+  line-height: 1.4;
+}
+</style>

+ 108 - 64
src/views/monitor/job/index.vue

@@ -35,12 +35,9 @@
       <el-col :span="1.5">
       <el-col :span="1.5">
         <el-button type="danger" plain icon="el-icon-delete" size="mini" :disabled="multiple" @click="handleDelete" v-hasPermi="['monitor:job:remove']">删除</el-button>
         <el-button type="danger" plain icon="el-icon-delete" size="mini" :disabled="multiple" @click="handleDelete" v-hasPermi="['monitor:job:remove']">删除</el-button>
       </el-col>
       </el-col>
-      <el-col :span="1.5">
-        <el-button type="info" plain icon="el-icon-notebook-2" size="mini" @click="handleTaskRegistry" v-hasPermi="['monitor:job:add']">Bean注册表</el-button>
-      </el-col>
-      <el-col :span="1.5">
-        <el-button type="primary" plain icon="el-icon-user" size="mini" @click="handleTenantJobConfig" v-hasPermi="['monitor:job:edit']">租户任务配置</el-button>
-      </el-col>
+<!--      <el-col :span="1.5">-->
+<!--        <el-button type="primary" plain icon="el-icon-user" size="mini" @click="handleTenantJobConfig" v-hasPermi="['monitor:job:edit']">租户任务配置</el-button>-->
+<!--      </el-col>-->
       <el-col :span="1.5">
       <el-col :span="1.5">
         <el-button type="info" plain icon="el-icon-s-operation" size="mini" @click="handleJobLog" v-hasPermi="['monitor:job:query']">任务日志</el-button>
         <el-button type="info" plain icon="el-icon-s-operation" size="mini" @click="handleJobLog" v-hasPermi="['monitor:job:query']">任务日志</el-button>
       </el-col>
       </el-col>
@@ -79,6 +76,7 @@
         <template slot-scope="scope">
         <template slot-scope="scope">
           <el-button size="mini" type="text" icon="el-icon-edit" @click="handleUpdate(scope.row)" v-hasPermi="['monitor:job:edit']">修改</el-button>
           <el-button size="mini" type="text" icon="el-icon-edit" @click="handleUpdate(scope.row)" v-hasPermi="['monitor:job:edit']">修改</el-button>
           <el-button size="mini" type="text" icon="el-icon-delete" @click="handleDelete(scope.row)" v-hasPermi="['monitor:job:remove']">删除</el-button>
           <el-button size="mini" type="text" icon="el-icon-delete" @click="handleDelete(scope.row)" v-hasPermi="['monitor:job:remove']">删除</el-button>
+          <el-button size="mini" type="text" icon="el-icon-connection" @click="handleAssignTenant(scope.row)" v-hasPermi="['monitor:job:edit']">分配</el-button>
           <el-button size="mini" type="text" icon="el-icon-s-operation" @click="handleRowJobLog(scope.row)" v-hasPermi="['monitor:job:query']">日志</el-button>
           <el-button size="mini" type="text" icon="el-icon-s-operation" @click="handleRowJobLog(scope.row)" v-hasPermi="['monitor:job:query']">日志</el-button>
         </template>
         </template>
       </el-table-column>
       </el-table-column>
@@ -121,11 +119,7 @@
                   <i class="el-icon-question"></i>
                   <i class="el-icon-question"></i>
                 </el-tooltip>
                 </el-tooltip>
               </span>
               </span>
-              <el-input v-model="form.invokeTarget" placeholder="请输入调用目标字符串">
-                <template slot="append">
-                  <el-button @click="openRegistry = true; initRegistry()">从注册表选择</el-button>
-                </template>
-              </el-input>
+              <el-input v-model="form.invokeTarget" placeholder="请输入调用目标字符串" />
             </el-form-item>
             </el-form-item>
           </el-col>
           </el-col>
           <el-col :span="24">
           <el-col :span="24">
@@ -191,37 +185,6 @@
       <crontab @hide="openCron=false" @fill="crontabFill" :expression="expression"></crontab>
       <crontab @hide="openCron=false" @fill="crontabFill" :expression="expression"></crontab>
     </el-dialog>
     </el-dialog>
 
 
-    <!-- Bean 注册表 -->
-    <el-dialog title="可调度 Bean 方法(invoke_target 参考)" :visible.sync="openRegistry" width="960px" append-to-body @open="initRegistry">
-      <el-form :model="registryQueryParams" ref="registryQueryForm" :inline="true" size="small">
-        <el-form-item label="Bean" prop="beanName">
-          <el-input v-model="registryQueryParams.beanName" placeholder="Bean 名称" clearable @keyup.enter.native="handleRegistryQuery" />
-        </el-form-item>
-        <el-form-item label="方法" prop="methodName">
-          <el-input v-model="registryQueryParams.methodName" placeholder="方法名" clearable @keyup.enter.native="handleRegistryQuery" />
-        </el-form-item>
-        <el-form-item label="调用目标" prop="invokeTarget">
-          <el-input v-model="registryQueryParams.invokeTarget" placeholder="invoke_target" clearable @keyup.enter.native="handleRegistryQuery" />
-        </el-form-item>
-        <el-form-item>
-          <el-button type="primary" icon="el-icon-search" size="mini" @click="handleRegistryQuery">搜索</el-button>
-          <el-button icon="el-icon-refresh" size="mini" @click="resetRegistryQuery">重置</el-button>
-        </el-form-item>
-      </el-form>
-      <el-table v-loading="registryLoading" :data="registryList" max-height="420">
-        <el-table-column label="Bean" prop="beanName" width="180" show-overflow-tooltip />
-        <el-table-column label="类名" prop="className" width="160" show-overflow-tooltip />
-        <el-table-column label="方法" prop="methodName" width="160" show-overflow-tooltip />
-        <el-table-column label="调用目标" prop="invokeTarget" show-overflow-tooltip />
-        <el-table-column label="操作" width="100" align="center">
-          <template slot-scope="scope">
-            <el-button type="text" size="mini" @click="applyInvokeTarget(scope.row)">选用</el-button>
-          </template>
-        </el-table-column>
-      </el-table>
-      <pagination v-show="registryTotal > 0" :total="registryTotal" :page.sync="registryQueryParams.pageNum" :limit.sync="registryQueryParams.pageSize" @pagination="getRegistryList" />
-    </el-dialog>
-
     <!-- 租户任务配置 -->
     <!-- 租户任务配置 -->
     <el-dialog title="租户定时任务配置" :visible.sync="openTenantJob" width="960px" append-to-body @open="loadTenantJobDialog">
     <el-dialog title="租户定时任务配置" :visible.sync="openTenantJob" width="960px" append-to-body @open="loadTenantJobDialog">
       <el-form :inline="true" size="small">
       <el-form :inline="true" size="small">
@@ -256,13 +219,36 @@
       <el-empty v-if="tenantJobForm.tenantId && !tenantJobLoading && !tenantJobConfigList.length" description="暂未同步,请点击「同步到租户库」按钮" />
       <el-empty v-if="tenantJobForm.tenantId && !tenantJobLoading && !tenantJobConfigList.length" description="暂未同步,请点击「同步到租户库」按钮" />
       <el-empty v-if="!tenantJobForm.tenantId" description="请先选择租户" />
       <el-empty v-if="!tenantJobForm.tenantId" description="请先选择租户" />
     </el-dialog>
     </el-dialog>
+
+    <!-- 分配租户弹窗 -->
+    <el-dialog :title="'分配租户 — ' + assignTemplate.jobName" :visible.sync="openAssignTenant" width="680px" append-to-body @open="loadAssignTenantDialog">
+      <el-form :inline="true" size="small">
+        <el-form-item>
+          <el-input v-model="assignTenantSearch" placeholder="搜索租户" clearable size="small" style="width: 220px" @input="handleAssignTenantSearch" />
+        </el-form-item>
+        <el-form-item>
+          <el-checkbox v-model="selectAllTenants" @change="handleSelectAllTenants">全选</el-checkbox>
+        </el-form-item>
+        <el-form-item>
+          <el-button type="primary" size="mini" :loading="assignTenantSaving" @click="submitAssignTenant">保存分配</el-button>
+        </el-form-item>
+      </el-form>
+      <el-checkbox-group v-model="selectedTenantIds" v-loading="assignTenantLoading" style="display:flex; flex-wrap:wrap; gap:4px 0;">
+        <el-checkbox
+          v-for="t in filteredAssignTenants"
+          :key="t.id"
+          :label="t.id"
+          style="width:50%; margin-right:0;"
+        >{{ t.tenantName + ' (' + t.tenantCode + ')' }}</el-checkbox>
+      </el-checkbox-group>
+      <el-empty v-if="!assignTenantLoading && !filteredAssignTenants.length" description="无可用租户" />
+    </el-dialog>
   </div>
   </div>
 </template>
 </template>
 
 
 <script>
 <script>
 import { listTemplate, getTemplate, addTemplate, updateTemplate, delTemplate } from "@/api/monitor/jobTemplate";
 import { listTemplate, getTemplate, addTemplate, updateTemplate, delTemplate } from "@/api/monitor/jobTemplate";
-import { listTaskRegistry } from "@/api/monitor/taskRegistry";
-import { getTenantJobConfig, updateTenantJobStatus, syncTenantJob, syncAllTenantJob } from "@/api/monitor/tenantJob";
+import { getTenantJobConfig, updateTenantJobStatus, syncTenantJob, syncAllTenantJob, saveTenantJobConfig, listTenantJobConfig } from "@/api/monitor/tenantJob";
 import { tenantList } from "@/api/tenant/tenant";
 import { tenantList } from "@/api/tenant/tenant";
 import Crontab from '@/components/Crontab'
 import Crontab from '@/components/Crontab'
 
 
@@ -282,18 +268,22 @@ export default {
       open: false,
       open: false,
       openCron: false,
       openCron: false,
       expression: "",
       expression: "",
-      // Bean 注册表
-      openRegistry: false,
-      registryLoading: false,
-      registryList: [],
-      registryTotal: 0,
-      registryQueryParams: { pageNum: 1, pageSize: 10, beanName: undefined, methodName: undefined, invokeTarget: undefined },
       // 租户任务配置
       // 租户任务配置
       openTenantJob: false,
       openTenantJob: false,
       tenantJobLoading: false,
       tenantJobLoading: false,
       tenantJobConfigList: [],
       tenantJobConfigList: [],
       tenantOptions: [],
       tenantOptions: [],
       tenantJobForm: { tenantId: undefined },
       tenantJobForm: { tenantId: undefined },
+      // 分配租户弹窗
+      openAssignTenant: false,
+      assignTenantLoading: false,
+      assignTenantSaving: false,
+      assignTemplate: {},
+      assignTenantSearch: '',
+      selectAllTenants: false,
+      selectedTenantIds: [],
+      previousSelectedTenantIds: [],
+      allTenants: [],
       // 字典
       // 字典
       jobGroupOptions: [],
       jobGroupOptions: [],
       // 查询参数
       // 查询参数
@@ -350,20 +340,6 @@ export default {
       const logPath = this.$route.path.startsWith('/admin/') ? '/admin/shezhi/jobLog' : '/monitor/jobLog';
       const logPath = this.$route.path.startsWith('/admin/') ? '/admin/shezhi/jobLog' : '/monitor/jobLog';
       this.$router.push({ path: logPath, query: { jobName: row.jobName } });
       this.$router.push({ path: logPath, query: { jobName: row.jobName } });
     },
     },
-    // Bean 注册表
-    handleTaskRegistry() { this.openRegistry = true; },
-    initRegistry() { this.registryQueryParams.pageNum = 1; this.getRegistryList(); },
-    getRegistryList() {
-      this.registryLoading = true;
-      listTaskRegistry(this.registryQueryParams).then(res => { this.registryList = res.rows || []; this.registryTotal = res.total || 0; this.registryLoading = false; }).catch(() => { this.registryLoading = false; });
-    },
-    handleRegistryQuery() { this.registryQueryParams.pageNum = 1; this.getRegistryList(); },
-    resetRegistryQuery() { this.registryQueryParams = { pageNum: 1, pageSize: 10, beanName: undefined, methodName: undefined, invokeTarget: undefined }; this.getRegistryList(); },
-    applyInvokeTarget(row) {
-      if (!this.open) { this.handleAdd(); }
-      this.form.invokeTarget = row.invokeTarget;
-      this.openRegistry = false;
-    },
     // 模板 CRUD
     // 模板 CRUD
     handleAdd() { this.reset(); this.open = true; this.title = "添加任务模板"; },
     handleAdd() { this.reset(); this.open = true; this.title = "添加任务模板"; },
     handleUpdate(row) {
     handleUpdate(row) {
@@ -415,6 +391,74 @@ export default {
       this.$confirm("确认将全部租户的任务配置同步到各租户库?", "提示", { type: "warning" }).then(() => {
       this.$confirm("确认将全部租户的任务配置同步到各租户库?", "提示", { type: "warning" }).then(() => {
         return syncAllTenantJob();
         return syncAllTenantJob();
       }).then(res => { const d = res.data || {}; this.msgSuccess("同步完成:成功 " + (d.successCount || 0) + ",失败 " + (d.failCount || 0)); }).catch(() => {});
       }).then(res => { const d = res.data || {}; this.msgSuccess("同步完成:成功 " + (d.successCount || 0) + ",失败 " + (d.failCount || 0)); }).catch(() => {});
+    },
+    // 分配租户
+    handleAssignTenant(row) {
+      this.assignTemplate = row
+      this.openAssignTenant = true
+    },
+    loadAssignTenantDialog() {
+      this.assignTenantLoading = true
+      this.assignTenantSearch = ''
+      this.selectAllTenants = false
+      this.selectedTenantIds = []
+      // 加载全部租户(与 tenantJobConfig 弹窗保持一致)
+      tenantList({}).then(res => {
+        this.allTenants = res.data || res.rows || []
+        this.assignTenantLoading = false
+        // 异步查询该模板已分配了哪些租户
+        listTenantJobConfig({ templateId: this.assignTemplate.templateId, status: 0, pageSize: 999 }).then(res2 => {
+          // 兼容多种响应格式:TableDataInfo { rows } / AjaxResult { data } / 直接数组
+          let rows = res2.rows || res2.data || (Array.isArray(res2) ? res2 : [])
+          console.log('分配租户 — 已分配查询结果 rows:', rows)
+          this.selectedTenantIds = rows.filter(r => String(r.status) === '0').map(r => Number(r.tenantId))
+          this.previousSelectedTenantIds = [...this.selectedTenantIds]
+          this.selectAllTenants = this.selectedTenantIds.length === this.allTenants.length && this.allTenants.length > 0
+        }).catch(() => {})
+      }).catch(() => { this.assignTenantLoading = false })
+    },
+    handleAssignTenantSearch() {},
+    handleSelectAllTenants(val) {
+      this.selectedTenantIds = val ? this.allTenants.map(t => t.id) : []
+    },
+    submitAssignTenant() {
+      this.assignTenantSaving = true
+      // 只处理选择状态发生变化的租户,避免覆盖其他模板的分配
+      const promises = []
+      const prevIds = this.previousSelectedTenantIds || []
+      this.allTenants.forEach(t => {
+        const isSelected = this.selectedTenantIds.includes(t.id)
+        const wasSelected = prevIds.includes(t.id)
+        if (isSelected === wasSelected) return  // 无变化,跳过
+        const p = getTenantJobConfig(t.id).then(res => {
+          const currentIds = (res.data || []).map(c => c.templateId)
+          const newIds = isSelected
+            ? [...new Set([...currentIds, this.assignTemplate.templateId])]
+            : currentIds.filter(id => id !== this.assignTemplate.templateId)
+          return saveTenantJobConfig({ tenantId: t.id, templateIds: newIds, status: '0' })
+        })
+        promises.push(p)
+      })
+      if (promises.length === 0) {
+        this.assignTenantSaving = false
+        this.openAssignTenant = false
+        return
+      }
+      Promise.all(promises).then(() => {
+        this.msgSuccess('分配成功')
+        this.assignTenantSaving = false
+        this.openAssignTenant = false
+      }).catch(() => { this.assignTenantSaving = false })
+    }
+  },
+  computed: {
+    filteredAssignTenants() {
+      if (!this.assignTenantSearch) return this.allTenants
+      const kw = this.assignTenantSearch.toLowerCase()
+      return this.allTenants.filter(t =>
+        (t.tenantName || '').toLowerCase().includes(kw) ||
+        (t.tenantCode || '').toLowerCase().includes(kw)
+      )
     }
     }
   }
   }
 };
 };