index.vue 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293
  1. <template>
  2. <div class="page">
  3. <el-card shadow="never">
  4. <el-form inline>
  5. <!-- 名称 -->
  6. <el-form-item :label="$t('message.formI18nLabel.name1')">
  7. <!-- 请输入关键字 -->
  8. <el-input v-model="searchParams.keyWord" :placeholder="$t('message.ruleEngine.keywordPlaceholder')" clearable @keyup.enter="handleSearch" />
  9. </el-form-item>
  10. <!-- 类型 -->
  11. <el-form-item :label="$t('message.formI18nLabel.type')">
  12. <!-- 请选择类型 -->
  13. <el-select v-model="searchParams.types" :placeholder="$t('message.ruleEngine.typePlaceholder')" clearable @clear="() => (searchParams.types = -1)" @change="handleSearch">
  14. <!-- 主链 -->
  15. <el-option :label="$t('message.ruleEngine.mainChain')" :value="1" />
  16. <!-- 子链 -->
  17. <el-option :label="$t('message.ruleEngine.subChain')" :value="2" />
  18. <!-- 全部 -->
  19. <el-option :label="$t('message.ruleEngine.all')" :value="-1" />
  20. </el-select>
  21. </el-form-item>
  22. <!-- 状态 -->
  23. <el-form-item :label="$t('message.formI18nLabel.status')">
  24. <!-- 请选择状态 -->
  25. <el-select v-model="searchParams.status" :placeholder="$t('message.ruleEngine.statusPlaceholder')" clearable @clear="() => (searchParams.status = -1)" @change="handleSearch">
  26. <!-- 已启动 -->
  27. <el-option :label="$t('message.ruleEngine.started')" :value="1" />
  28. <!-- 已停止 -->
  29. <el-option :label="$t('message.ruleEngine.stopped')" :value="0" />
  30. <!-- 全部 -->
  31. <el-option :label="$t('message.ruleEngine.all')" :value="-1" />
  32. </el-select>
  33. </el-form-item>
  34. <el-form-item>
  35. <!-- 查询 -->
  36. <el-button type="primary" @click="handleSearch">
  37. <el-icon><ele-Search /></el-icon>
  38. {{$t('message.formI18nButton.query')}}
  39. </el-button>
  40. <!-- <el-button @click="handleReset">
  41. <el-icon><ele-Refresh /></el-icon>
  42. 重置
  43. </el-button> -->
  44. </el-form-item>
  45. <el-form-item>
  46. <!-- 新增规则编排 -->
  47. <el-button type="primary" v-auth="'add'" @click="addOrEdit()">
  48. <el-icon>
  49. <ele-FolderAdd />
  50. </el-icon>
  51. {{ $t('message.ruleEngine.addRule') }}
  52. </el-button>
  53. </el-form-item>
  54. </el-form>
  55. <el-table :data="tableData" style="width: 100%" v-loading="loading">
  56. <!-- 序号 -->
  57. <el-table-column type="index" :label="$t('message.tableI18nColumn.index')" width="80" align="center" />
  58. <!-- 类型 -->
  59. <el-table-column prop="types" :label="$t('message.formI18nLabel.type')" width="70" align="center">
  60. <template #default="scope">
  61. <!-- 主链 -->
  62. <el-tag size="small" v-if="scope.row.types == 1">{{$t('message.ruleEngine.mainChain')}}</el-tag>
  63. <!-- 子链 -->
  64. <el-tag type="success" size="small" v-else>{{$t('message.ruleEngine.subChain')}}</el-tag>
  65. </template>
  66. </el-table-column>
  67. <!-- 名称 -->
  68. <el-table-column prop="name" :label="$t('message.formI18nLabel.name1')" show-overflow-tooltip></el-table-column>
  69. <!-- 描述 -->
  70. <el-table-column prop="expound" :label="$t('message.formI18nLabel.desc')" show-overflow-tooltip></el-table-column>
  71. <!-- 创建时间 -->
  72. <el-table-column prop="createdAt" :label="$t('message.tableI18nColumn.createdAt')" min-width="100" align="center"></el-table-column>
  73. <!-- 状态 -->
  74. <el-table-column prop="status" :label="$t('message.formI18nLabel.status')" width="100" align="center">
  75. <template #default="scope">
  76. <!-- 已启动 -->
  77. <el-tag type="success" size="small" v-if="scope.row.status == 1">{{$t('message.ruleEngine.started')}}</el-tag>
  78. <!-- 已停止 -->
  79. <el-tag type="info" size="small" v-else>{{$t('message.ruleEngine.stopped')}}</el-tag>
  80. </template>
  81. </el-table-column>
  82. <!-- 操作 -->
  83. <el-table-column :label="$t('message.tableI18nColumn.operation')" width="200" align="center">
  84. <template #default="scope">
  85. <!-- 停止 -->
  86. <el-button size="small" text type="info" v-auth="'startOrStop'" v-if="scope.row.status" @click="setStatus(scope.row, 0)">{{ $t('message.ruleEngine.stop') }}</el-button>
  87. <!-- 启动 -->
  88. <el-button size="small" text type="primary" v-auth="'startOrStop'" v-else @click="setStatus(scope.row, 1)">{{ $t('message.ruleEngine.start') }}</el-button>
  89. <!-- 编辑 -->
  90. <el-button size="small" text type="primary" v-auth="'edit'" @click="addOrEdit(scope.row)">{{ $t('message.tableI18nAction.edit') }}</el-button>
  91. <!-- 规则编辑 -->
  92. <el-button size="small" text type="warning" @click="edit(scope.row)">{{ $t('message.ruleEngine.ruleEdit') }}</el-button>
  93. <!-- 删除 -->
  94. <el-button size="small" text type="info" v-auth="'del'" @click="onDel(scope.row)">{{ $t('message.tableI18nAction.delete') }}</el-button>
  95. </template>
  96. </el-table-column>
  97. </el-table>
  98. <pagination v-if="params.total" :total="params.total" v-model:page="params.pageNum" v-model:limit="params.pageSize" @pagination="getList()" />
  99. <EditForm :model="model" ref="editFormRef" @getList="getList(1)"></EditForm>
  100. </el-card>
  101. </div>
  102. </template>
  103. <script lang="ts" setup>
  104. import { ref, reactive, watch, computed } from "vue";
  105. import api from "/@/api/rule";
  106. import { ElMessageBox, ElMessage } from "element-plus";
  107. import { useSearch } from "/@/hooks/useCommon";
  108. import EditForm from "./edit.vue";
  109. import axios from "axios";
  110. import { getToken } from "/@/utils/auth";
  111. import { getRuleServerOrigin } from "/@/utils/origin";
  112. import { useI18n } from 'vue-i18n';
  113. // 国际化
  114. const { locale, t } = useI18n();
  115. const currentLocale = computed(() => locale.value);
  116. const editFormRef = ref();
  117. // 规则引擎模式 node-red、 sagoo-rule
  118. const model: "node-red" | "sagoo-rule" = import.meta.env.VITE_RULE_MODEL;
  119. const searchParams = reactive({
  120. keyWord: "",
  121. types: -1,
  122. status: -1,
  123. });
  124. // 监听搜索参数变化,确保在API请求中正确传递搜索条件
  125. watch(
  126. searchParams,
  127. (newVal: any) => {
  128. // 处理搜索参数的值
  129. for (const key in newVal) {
  130. if (newVal[key] === "" || newVal[key] === null) {
  131. // 如果是类型或状态字段,在清除时设置为-1(全部)
  132. if (key === "types" || key === "status") {
  133. params[key] = -1;
  134. searchParams[key] = -1; // 同步更新searchParams
  135. } else {
  136. delete params[key];
  137. }
  138. } else {
  139. params[key] = newVal[key];
  140. }
  141. }
  142. },
  143. { deep: true }
  144. );
  145. const { params, tableData, getList, loading } = useSearch<any[]>(api.getList, "Data", searchParams);
  146. const headers = {
  147. Authorization: "Bearer " + getToken(),
  148. };
  149. const flowsUrl = window.location.origin + "/rule-engine/flows";
  150. getList();
  151. // 搜索
  152. const handleSearch = () => {
  153. getList(1);
  154. };
  155. // 重置功能已在模板中被注释掉
  156. // 如果需要重新启用重置功能,请取消注释并使用以下代码:
  157. /*
  158. const handleReset = () => {
  159. searchParams.keyWord = '';
  160. searchParams.types = -1;
  161. searchParams.status = -1;
  162. getList(1);
  163. };
  164. */
  165. const addOrEdit = async (row?: any) => {
  166. if (row) {
  167. editFormRef.value.open(row);
  168. return;
  169. } else {
  170. editFormRef.value.open();
  171. }
  172. };
  173. const setStatus = async (row: any, status: number) => {
  174. if (model === "sagoo-rule") {
  175. axios
  176. .get(getRuleServerOrigin(`/api/v1/rule/${row.flowId}/${status ? "enable" : "stop"}`), { headers })
  177. .then(() => {
  178. api
  179. .setStatus(row.id, status)
  180. .then(() => {
  181. // 操作成功
  182. ElMessage.success(t('message.tableI18nConfirm.handleSuccess'));
  183. getList();
  184. })
  185. .catch(() => {
  186. // 操作失败
  187. ElMessage.error(t('message.tableI18nConfirm.handleFailed'));
  188. });
  189. })
  190. .catch(() => {
  191. // 操作失败
  192. ElMessage.error(t('message.tableI18nConfirm.handleFailed'));
  193. });
  194. } else {
  195. // 找到所有规则
  196. const { data: flows } = await axios.get(flowsUrl, { headers });
  197. const flow = flows.find((item: any) => item.id === row.flowId);
  198. if (!flow) {
  199. // 规则不存在
  200. ElMessage.error(t('message.ruleEngine.ruleNotExist'));
  201. return;
  202. }
  203. // 改变指定规则状态
  204. flow.disabled = status ? false : true;
  205. // 设置规则状态
  206. await axios.post(flowsUrl, flows, { headers });
  207. api
  208. .setStatus(row.id, status)
  209. .then(() => {
  210. // 操作成功
  211. ElMessage.success(t('message.tableI18nConfirm.handleSuccess'));
  212. getList();
  213. })
  214. .catch(() => {
  215. // 操作失败
  216. ElMessage.error(t('message.tableI18nConfirm.handleFailed'));
  217. });
  218. }
  219. };
  220. const edit = async (row: any) => {
  221. if (model == "sagoo-rule") {
  222. localStorage.setItem("auth-tokens", `{"access_token":"${getToken()}"}`);
  223. const url = "/plugin/rule/index.html#" + row.flowId;
  224. window.open(url);
  225. } else if (model == "node-red") {
  226. localStorage.setItem("auth-tokens", `{"access_token":"${getToken()}"}`);
  227. const url = "/rule-engine/#flow/" + row.flowId;
  228. window.open(url);
  229. }
  230. };
  231. const onDel = (row: any) => {
  232. // 此操作将删除:“${row.name}”,是否继续?
  233. ElMessageBox.confirm(
  234. t('message.ruleEngine.deleteRuleMessage', { name: row.name }),
  235. t('message.tableI18nConfirm.deleteTitle'), {
  236. confirmButtonText: t('message.tableI18nConfirm.confirmText'),
  237. cancelButtonText: t('message.tableI18nConfirm.cancelText'),
  238. type: 'warning',
  239. }).then(async () => {
  240. if (model == "sagoo-rule") {
  241. await axios.delete(getRuleServerOrigin("/api/v1/rules/" + row.flowId), { headers }).catch(() => {
  242. // 规则不存在
  243. ElMessage.error(t('message.ruleEngine.ruleNotExist'));
  244. });
  245. } else if (model == "node-red") {
  246. // 找到所有规则
  247. const { data: flows } = await axios.get(flowsUrl, { headers });
  248. const flowIndex = flows.findIndex((item: any) => item.id === row.flowId);
  249. if (flowIndex >= 0) {
  250. // 删除指定规则
  251. flows.splice(flowIndex, 1);
  252. // 删除当前规则下的各个节点信息
  253. const newFlows = flows.filter((item: any) => {
  254. if (item.z === row.flowId) {
  255. return false;
  256. } else {
  257. return true;
  258. }
  259. });
  260. // 设置规则状态
  261. await axios.post(flowsUrl, newFlows, { headers });
  262. }
  263. }
  264. await api.del([row.id as string]);
  265. // 删除成功
  266. ElMessage.success(t('message.tableI18nConfirm.deleteSuccess'));
  267. getList();
  268. });
  269. };
  270. </script>