index.vue 9.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347
  1. <template>
  2. <div class="bm-main-box">
  3. <div class="flex items-center">
  4. <div class="bm-main-box-title">{{ $route.meta.title }}</div>
  5. <div class="ml-auto flex items-center gap-[var(--czr-gap)]">
  6. <CzrForm class="bm-filter" label-width="0px" @handleEnter="onSearch">
  7. <CzrFormColumn
  8. width="6.68rem"
  9. class="__czr-table-form-column"
  10. :span="24"
  11. label-width="0px"
  12. v-model:param="state.query.form.modeType"
  13. link="select"
  14. :options="DictionaryStore.modelTypes.list"
  15. placeholder="模型类型"
  16. />
  17. <CzrFormColumn
  18. width="6.68rem"
  19. class="__czr-table-form-column"
  20. :span="24"
  21. label-width="0px"
  22. v-model:param="state.query.form.status"
  23. link="select"
  24. :options="[
  25. { label: '停用', value: 0 },
  26. { label: '启用', value: 1 },
  27. ]"
  28. placeholder="模型状态"
  29. />
  30. <CzrFormColumn
  31. width="15.63rem"
  32. class="__czr-table-form-column"
  33. :span="24"
  34. label-width="0px"
  35. v-model:param="state.text"
  36. placeholder="输入关键词以检索"
  37. :prefix-icon="Search"
  38. />
  39. <CzrButton type="add" @click="onAdd" />
  40. </CzrForm>
  41. </div>
  42. </div>
  43. <div
  44. class="mt-[1rem] flex-1 overflow-hidden"
  45. v-loading="state.query.loading"
  46. >
  47. <CzrTableCard
  48. class="table-card"
  49. :page="state.query.page.pageNum"
  50. :pageSize="state.query.page.pageSize"
  51. :total="state.query.result.total"
  52. :data="state.query.result.data"
  53. @handlePage="onPage"
  54. :col="2"
  55. >
  56. <template #model="{ row, index }">
  57. <div
  58. class="model __hover"
  59. @click="
  60. $router.push({
  61. name: 'd91af45a-7258-4b1e-8e0b-178e8b66d847',
  62. params: {
  63. id: row.id,
  64. },
  65. })
  66. "
  67. >
  68. <div class="flex">
  69. <img
  70. src="@/assets/images/model-default-logo.png"
  71. class="mr-[var(--czr-gap)] h-[3.25rem] w-[3.25rem]"
  72. />
  73. <div class="flex flex-1 flex-col justify-around overflow-hidden">
  74. <div class="text-[1.25rem] font-bold text-[#2E3238]" v-title>
  75. {{ row.name }}
  76. </div>
  77. <div class="flex">
  78. <div
  79. class="flex h-[1.25rem] items-center justify-center rounded-[0.13rem] bg-gradient-to-r from-[#FF9E2D] to-[#FFB92D] px-[0.38rem] text-[0.63rem] font-bold text-[#ffffff]"
  80. >
  81. {{ DictionaryStore.modelTypes.map.get(row.type) }}
  82. </div>
  83. </div>
  84. </div>
  85. <div class="mt-[0.25rem] ml-auto">
  86. <div
  87. v-if="row.status == 1"
  88. class="flex h-[1.56rem] w-[3.75rem] items-center justify-center rounded-[1.25rem] bg-gradient-to-r from-[#D5F9FE] to-[#E0DAFF] text-[0.75rem] font-bold text-[#1E3F92]"
  89. >
  90. 已启用
  91. </div>
  92. </div>
  93. </div>
  94. <div
  95. class="mt-[var(--czr-gap)] mb-auto h-[3rem] text-[0.88rem] text-[#606266]"
  96. style="line-height: 1.4rem"
  97. v-title="{ lines: 2 }"
  98. >
  99. {{ row.description }}
  100. </div>
  101. <div
  102. class="mt-[0.5rem] flex items-center gap-[var(--czr-gap)] text-[0.75rem] text-[#6F7889]"
  103. >
  104. <div>
  105. {{ DictionaryStore.modelProvides.map.get(row.pluginClass) }}
  106. </div>
  107. <div>|</div>
  108. <div>(创建单位)</div>
  109. <div>|</div>
  110. <div>{{ row.createNickName }}</div>
  111. <div>|</div>
  112. <div>{{ YMDHms(row.updateTime) }}</div>
  113. </div>
  114. <div
  115. class="mt-[0.5rem] flex items-center gap-[var(--czr-gap)] text-[0.75rem] text-[#6F7889]"
  116. >
  117. <div class="ml-auto" @click.capture.stop="onSwitch(row)">
  118. <a-switch
  119. v-model:checked="row.status"
  120. checked-children="启用"
  121. un-checked-children="停用"
  122. :checked-value="1"
  123. :un-checked-value="0"
  124. size="small"
  125. />
  126. </div>
  127. <template v-if="row.status == 0">
  128. <el-tooltip content="编辑" effect="light" placement="top">
  129. <SvgIcon
  130. name="czr_edit"
  131. size="14"
  132. class="__hover"
  133. @click.stop="onEdit(row)"
  134. />
  135. </el-tooltip>
  136. <el-tooltip content="删除" effect="light" placement="top">
  137. <SvgIcon
  138. name="czr_del"
  139. size="16"
  140. class="__hover"
  141. @click.stop="onDel(row)"
  142. />
  143. </el-tooltip>
  144. </template>
  145. </div>
  146. </div>
  147. </template>
  148. </CzrTableCard>
  149. </div>
  150. <detailCom
  151. v-model:show="state.detail.show"
  152. :transfer="state.detail.transfer"
  153. @refresh="onSearch"
  154. />
  155. </div>
  156. </template>
  157. <script setup lang="ts">
  158. import { getCurrentInstance, onMounted, reactive, ref, watch } from 'vue'
  159. import { Search } from '@element-plus/icons-vue'
  160. import { debounce } from 'lodash'
  161. import { useAppStore, useDialogStore, useDictionaryStore } from '@/stores'
  162. import { ElMessage } from 'element-plus'
  163. import detailCom from './detail.vue'
  164. import {
  165. pluginDel,
  166. pluginGetInstanceList,
  167. pluginUpdateStatus,
  168. } from '@/api/modules/model'
  169. import { YMDHms } from '@/utils/czr-util'
  170. const AppStore = useAppStore()
  171. const DialogStore = useDialogStore()
  172. const DictionaryStore = useDictionaryStore()
  173. const emit = defineEmits([])
  174. const props = defineProps({})
  175. const { proxy }: any = getCurrentInstance()
  176. const state: any = reactive({
  177. text: '',
  178. query: {
  179. init: false,
  180. loading: false,
  181. page: {
  182. pageNum: 1,
  183. pageSize: 20,
  184. },
  185. form: {},
  186. formReal: {},
  187. result: {
  188. total: 0,
  189. data: [],
  190. },
  191. },
  192. detail: {
  193. show: false,
  194. transfer: {},
  195. },
  196. })
  197. const setText = debounce((v) => {
  198. state.query.form.keyword = v
  199. }, 1000)
  200. watch(
  201. () => state.text,
  202. (n) => {
  203. setText(n)
  204. },
  205. )
  206. watch(
  207. () => state.query.form,
  208. (n) => {
  209. if (state.query.init) {
  210. onSearch()
  211. }
  212. },
  213. { deep: true },
  214. )
  215. const onPage = (pageNum, pageSize) => {
  216. setTimeout(() => {
  217. state.query.init = true
  218. }, 100)
  219. state.query.page = {
  220. pageNum: pageNum,
  221. pageSize: pageSize,
  222. }
  223. const params = {
  224. page: state.query.page.pageNum,
  225. size: state.query.page.pageSize,
  226. }
  227. // 添加表单参数
  228. for (const [k, v] of Object.entries(state.query.formReal)) {
  229. if (proxy.$czrUtil.isValue(v)) {
  230. params[k] = v
  231. }
  232. }
  233. state.query.loading = true
  234. pluginGetInstanceList(params)
  235. .then(({ data }: any) => {
  236. state.query.result.total = data.total
  237. state.query.result.data = data.records
  238. })
  239. .catch(({ message }: any) => {
  240. ElMessage.error(message)
  241. })
  242. .finally(() => {
  243. state.query.loading = false
  244. })
  245. }
  246. const onSearch = () => {
  247. state.query.formReal = JSON.parse(JSON.stringify(state.query.form))
  248. onPage(1, state.query.page.pageSize)
  249. }
  250. const onReset = () => {
  251. state.query.page = {
  252. pageNum: 1,
  253. pageSize: 20,
  254. }
  255. state.query.form = {}
  256. onSearch()
  257. }
  258. const onAdd = () => {
  259. state.detail.transfer = {
  260. mode: 'add',
  261. }
  262. state.detail.show = true
  263. }
  264. const onEdit = (row) => {
  265. state.detail.transfer = {
  266. mode: 'edit',
  267. id: row.id,
  268. }
  269. state.detail.show = true
  270. }
  271. const onDel = (row: any) => {
  272. DialogStore.confirm({
  273. title: '删除确认',
  274. content: `${row.p6}个应用正在使用该大模型,删除将导致不可用,请确认是否删除`,
  275. onSubmit: () => {
  276. pluginDel(row.id)
  277. .then(() => {
  278. ElMessage.success('删除成功!')
  279. })
  280. .catch(({ message }: any) => {
  281. ElMessage.error(message)
  282. })
  283. .finally(() => {
  284. onSearch()
  285. })
  286. },
  287. })
  288. }
  289. const onSwitch = (row) => {
  290. if (row.status == 1) {
  291. DialogStore.confirm({
  292. title: '停用确认',
  293. content: `${row.p6}个应用正在使用该大模型,停用将导致不可用,请确认是否停用`,
  294. onSubmit: () => {
  295. pluginUpdateStatus({ ids: [row.id], status: 0 })
  296. .then(() => {
  297. ElMessage.success('停用成功!')
  298. })
  299. .catch(({ message }: any) => {
  300. ElMessage.error(message)
  301. })
  302. .finally(() => {
  303. onSearch()
  304. })
  305. },
  306. onCancel: () => {},
  307. })
  308. } else {
  309. pluginUpdateStatus({ ids: [row.id], status: 1 })
  310. .then(() => {
  311. ElMessage.success('启用成功!')
  312. })
  313. .catch(({ message }: any) => {
  314. ElMessage.error(message)
  315. })
  316. .finally(() => {
  317. onSearch()
  318. })
  319. }
  320. }
  321. onMounted(() => {
  322. initDictionary()
  323. onReset()
  324. })
  325. const initDictionary = () => {
  326. DictionaryStore.initModelTypes()
  327. DictionaryStore.initModelProvides()
  328. }
  329. </script>
  330. <style lang="scss" scoped>
  331. .model {
  332. width: 100%;
  333. background-image: url('@/assets/images/model-icon-7.png');
  334. background-repeat: no-repeat;
  335. background-size: 100% 100%;
  336. padding: 1rem 1.5rem;
  337. border-radius: var(--czr-gap);
  338. box-shadow: 0rem 0.25rem 0.63rem 0rem rgba(40, 83, 247, 0.05);
  339. border: var(--czr-border);
  340. display: flex;
  341. flex-direction: column;
  342. }
  343. </style>