You can not select more than 25 topics Topics must start with a chinese character,a letter or number, can include dashes ('-') and can be up to 35 characters long.

index.vue 16 kB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451
  1. <template>
  2. <div>
  3. <div class="title"><span>{{ $t('resourcesManagement.resSpecificationAndPriceManagement') }}</span></div>
  4. <div class="tools-bar">
  5. <div>
  6. <el-select class="select" size="medium" v-model="selQueue" @change="selectChange">
  7. <el-option v-for="item in queueList" :key="item.k" :label="item.v" :value="item.k" />
  8. </el-select>
  9. <el-select class="select" size="medium" v-model="selStatus" @change="selectChange">
  10. <el-option v-for="item in statusList" :key="item.k" :label="item.v" :value="item.k" />
  11. </el-select>
  12. </div>
  13. <div>
  14. <el-button size="medium" icon="el-icon-refresh" @click="syncComputerNetwork" v-loading="syncLoading">
  15. {{ $t('resourcesManagement.syncAiNetwork') }}</el-button>
  16. <el-button type="primary" icon="el-icon-plus" size="medium" @click="showDialog('add')">
  17. {{ $t('resourcesManagement.addResSpecificationBtn') }}</el-button>
  18. </div>
  19. </div>
  20. <div class="table-container">
  21. <div style="min-height:600px;">
  22. <el-table border :data="tableData" style="width: 100%" v-loading="loading" stripe>
  23. <el-table-column prop="ID" label="ID" align="center" header-align="center" width="60"></el-table-column>
  24. <el-table-column prop="SpecStr" :label="$t('resourcesManagement.resourceSpecification')" align="left"
  25. header-align="center" min-width="160">
  26. </el-table-column>
  27. <el-table-column prop="QueueInfo" :label="$t('resourcesManagement.resQueue')" align="center"
  28. header-align="center" min-width="100">
  29. </el-table-column>
  30. <el-table-column prop="SourceSpecId" :label="$t('resourcesManagement.sourceSpecCode')" align="center"
  31. header-align="center">
  32. </el-table-column>
  33. <el-table-column prop="AccCardsNum" :label="$t('resourcesManagement.accCardsNum')" align="center"
  34. header-align="center"></el-table-column>
  35. <el-table-column prop="CpuCores" :label="$t('resourcesManagement.cpuNum')" align="center"
  36. header-align="center"></el-table-column>
  37. <el-table-column prop="GPUMemGiB" :label="`${$t('resourcesManagement.gpuMem')}(GB)`" align="center"
  38. header-align="center"></el-table-column>
  39. <el-table-column prop="MemGiB" :label="`${$t('resourcesManagement.mem')}(GB)`" align="center"
  40. header-align="center"></el-table-column>
  41. <el-table-column prop="ShareMemGiB" :label="`${$t('resourcesManagement.shareMem')}(GB)`" align="center"
  42. header-align="center"></el-table-column>
  43. <el-table-column prop="UpdatedTimeStr" :label="$t('resourcesManagement.lastUpdateTime')" align="center"
  44. header-align="center"></el-table-column>
  45. <el-table-column prop="UnitPrice"
  46. :label="`${$t('resourcesManagement.unitPrice')}(${$t('resourcesManagement.point_hr')})`" align="center"
  47. header-align="center">
  48. <template slot-scope="scope">
  49. <span style="font-weight:600;font-size:14px;">{{ scope.row.UnitPrice }}</span>
  50. </template>
  51. </el-table-column>
  52. <el-table-column prop="StatusStr" :label="$t('resourcesManagement.status')" align="center"
  53. header-align="center" width="100">
  54. <template slot-scope="scope">
  55. <span :style="{ color: scope.row.Status == '2' ? 'rgb(82, 196, 26)' : 'rgb(245, 34, 45)' }">{{
  56. scope.row.StatusStr
  57. }}</span>
  58. </template>
  59. </el-table-column>
  60. <el-table-column :label="$t('operation')" align="center" header-align="center" width="100">
  61. <template slot-scope="scope">
  62. <span v-if="scope.row.Status == '1' && !scope.row.UnitPrice">
  63. <span class="op-btn" @click="showDialog('edit', scope.row)">{{
  64. $t('resourcesManagement.toSetPriceAndOnShelf')
  65. }}</span>
  66. </span>
  67. <span v-if="scope.row.Status == '2'">
  68. <span class="op-btn" @click="showDialog('edit', scope.row, true)">{{ $t('edit') }}</span>
  69. <span class="op-btn" @click="offShelfPrev(scope.row)">{{
  70. $t('resourcesManagement.toOffShelf')
  71. }}</span>
  72. </span>
  73. <span v-if="scope.row.Status == '3' || scope.row.Status == '1' && scope.row.UnitPrice">
  74. <span class="op-btn" @click="onShelf(scope.row)">{{
  75. $t('resourcesManagement.toOnShelf')
  76. }}</span>
  77. </span>
  78. </template>
  79. </el-table-column>
  80. <template slot="empty">
  81. <span style="font-size: 12px">{{
  82. loading ? $t('loading') : $t('noData')
  83. }}</span>
  84. </template>
  85. </el-table>
  86. </div>
  87. <div class="__r_p_pagination">
  88. <div style="margin-top: 2rem">
  89. <div class="center">
  90. <el-pagination background @current-change="currentChange" :current-page="pageInfo.curpage"
  91. :page-sizes="pageInfo.pageSizes" :page-size="pageInfo.pageSize"
  92. layout="total, sizes, prev, pager, next, jumper" :total="pageInfo.total">
  93. </el-pagination>
  94. </div>
  95. </div>
  96. </div>
  97. </div>
  98. <SpecificationDialog :visible.sync="specificationDialogShow" :type="specificationDialogType"
  99. :editOr="specificationDialogEditOr" :data="specificationDialogData" @confirm="specificationDialogConfirm">
  100. </SpecificationDialog>
  101. <BaseDialog :visible.sync="offShelfDialogShow" :width="`600px`" :title="$t('tips')">
  102. <div class="form">
  103. <div class="form-row" style="flex-direction:column;">
  104. <div class="content" style="margin:8px 0">{{ $t('resourcesManagement.offShelfDlgTip1') }}</div>
  105. <div class="content" style="margin:8px 0;font-weight: bold;">{{ offSelfDialogContent }}</div>
  106. <div class="content" style="margin:8px 0">{{ $t('resourcesManagement.offShelfDlgTip2') }}</div>
  107. </div>
  108. <div class="form-row" style="margin-top: 20px">
  109. <div class="content">
  110. <el-button type="primary" class="btn confirm-btn" @click="offShelf">{{ $t('confirm') }}</el-button>
  111. <el-button class="btn" @click="offShelfDialogShow = false">{{ $t('cancel') }}</el-button>
  112. </div>
  113. </div>
  114. </div>
  115. </BaseDialog>
  116. </div>
  117. </template>
  118. <script>
  119. import SpecificationDialog from '../components/SpecificationDialog.vue';
  120. import BaseDialog from '~/components/BaseDialog.vue';
  121. import { getResQueueCode, getResSpecificationList, updateResSpecification, syncResSpecification, getResSpecificationScenes } from '~/apis/modules/resources';
  122. import { SPECIFICATION_STATUS, CLUSTERS, ACC_CARD_TYPE } from '~/const';
  123. import { getListValueWithKey } from '~/utils';
  124. import { formatDate } from 'element-ui/lib/utils/date-util';
  125. export default {
  126. data() {
  127. return {
  128. selQueue: '',
  129. queueList: [{ k: '', v: this.$t('resourcesManagement.allResQueue') }],
  130. selStatus: '',
  131. statusList: [{ k: '', v: this.$t('resourcesManagement.allStatus') }, ...SPECIFICATION_STATUS],
  132. clusterList: [...CLUSTERS],
  133. accCardTypeList: [...ACC_CARD_TYPE],
  134. syncLoading: false,
  135. loading: false,
  136. tableData: [],
  137. pageInfo: {
  138. curpage: 1,
  139. pageSize: 10,
  140. pageSizes: [10],
  141. total: 0,
  142. },
  143. specificationDialogShow: false,
  144. specificationDialogType: 'add',
  145. specificationDialogEditOr: false,
  146. specificationDialogData: {},
  147. offShelfDialogShow: false,
  148. offShelfDialogData: {},
  149. offSelfDialogContent: '',
  150. };
  151. },
  152. components: { BaseDialog, SpecificationDialog },
  153. methods: {
  154. getQueueList() {
  155. getResQueueCode().then(res => {
  156. res = res.data;
  157. if (res.Code === 0) {
  158. const data = res.Data;
  159. const list = [];
  160. for (let i = 0, iLen = data.length; i < iLen; i++) {
  161. const item = data[i];
  162. list.push({
  163. k: item.ID,
  164. v: `${item.QueueCode}(${getListValueWithKey(this.clusterList, item.Cluster)} - ${item.AiCenterName})`,
  165. });
  166. }
  167. this.queueList.push(...list);
  168. }
  169. }).catch(err => {
  170. console.log(err);
  171. });
  172. },
  173. getTableData() {
  174. const params = {
  175. queue: this.selQueue,
  176. status: this.selStatus,
  177. page: this.pageInfo.curpage,
  178. pagesize: this.pageInfo.pageSize,
  179. };
  180. this.loading = true;
  181. getResSpecificationList(params).then(res => {
  182. this.loading = false;
  183. res = res.data;
  184. if (res.Code === 0) {
  185. const list = res.Data.List;
  186. const data = list.map((item) => {
  187. const Queue = item.Queue;
  188. const Spec = item.Spec;
  189. // const NGPU = `${Queue.ComputeResource}:${Spec.AccCardsNum === 0 ? '0' : Spec.AccCardsNum + '*' + getListValueWithKey(this.accCardTypeList, Queue.AccCardType)}`;
  190. const NGPU = `${Queue.ComputeResource}:${Spec.AccCardsNum + '*' + getListValueWithKey(this.accCardTypeList, Queue.AccCardType)}`;
  191. return {
  192. ...Spec,
  193. SourceSpecId: Spec.SourceSpecId || '--',
  194. SpecStr: `${NGPU}, CPU:${Spec.CpuCores}, ${this.$t('resourcesManagement.gpuMem')}:${Spec.GPUMemGiB}GB, ${this.$t('resourcesManagement.mem')}:${Spec.MemGiB}GB, ${this.$t('resourcesManagement.shareMem')}:${Spec.ShareMemGiB}GB`,
  195. QueueId: Queue.ID,
  196. QueueInfo: `${Queue.QueueCode}(${getListValueWithKey(this.clusterList, Queue.Cluster)} - ${Queue.AiCenterName})`,
  197. UpdatedTimeStr: formatDate(new Date(Spec.UpdatedTime * 1000), 'yyyy-MM-dd HH:mm:ss'),
  198. Status: Spec.Status.toString(),
  199. StatusStr: getListValueWithKey(this.statusList, Spec.Status.toString()),
  200. }
  201. });
  202. this.tableData = data;
  203. this.pageInfo.total = res.Data.TotalSize;
  204. }
  205. }).catch(err => {
  206. console.log(err);
  207. this.loading = false;
  208. });
  209. },
  210. syncComputerNetwork() {
  211. this.syncLoading = true;
  212. syncResSpecification().then(res => {
  213. this.syncLoading = false;
  214. res = res.data;
  215. if (res.Code === 0) {
  216. this.$message({
  217. type: 'success',
  218. message: this.$t('submittedSuccessfully')
  219. });
  220. this.getTableData();
  221. } else {
  222. this.$message({
  223. type: 'error',
  224. message: this.$t('submittedFailed')
  225. });
  226. }
  227. }).catch(err => {
  228. console.log(err);
  229. this.syncLoading = false;
  230. this.$message({
  231. type: 'error',
  232. message: this.$t('submittedFailed')
  233. });
  234. });
  235. },
  236. selectChange() {
  237. this.pageInfo.curpage = 1;
  238. this.getTableData();
  239. },
  240. currentChange(val) {
  241. this.pageInfo.curpage = val;
  242. this.getTableData();
  243. },
  244. showDialog(type, data, editOr) {
  245. this.specificationDialogType = type;
  246. this.specificationDialogEditOr = !!editOr;
  247. this.specificationDialogData = data ? { ...data } : {};
  248. this.specificationDialogShow = true;
  249. },
  250. specificationDialogConfirm() {
  251. this.specificationDialogShow = false;
  252. this.getTableData();
  253. },
  254. onShelf(data) {
  255. const type = 'on-shelf';
  256. this.$confirm(type === 'on-shelf' ? this.$t('resourcesManagement.onShelfConfirm') : this.$t('resourcesManagement.offShelfConfirm'), this.$t('tips'), {
  257. confirmButtonText: this.$t('confirm1'),
  258. cancelButtonText: this.$t('cancel'),
  259. type: 'warning',
  260. lockScroll: false,
  261. }).then(() => {
  262. updateResSpecification({
  263. ID: data.ID,
  264. action: type
  265. }).then(res => {
  266. res = res.data;
  267. if (res.Code === 0) {
  268. this.$message({
  269. type: 'success',
  270. message: this.$t('submittedSuccessfully')
  271. });
  272. this.getTableData();
  273. } else {
  274. if (type === 'on-shelf' && res.Code === 1001) {
  275. this.$message({
  276. type: 'info',
  277. message: this.$t('resourcesManagement.onShelfCode1001')
  278. });
  279. } else {
  280. this.$message({
  281. type: 'error',
  282. message: this.$t('submittedFailed')
  283. });
  284. }
  285. }
  286. }).catch(err => {
  287. console.log(err);
  288. this.$message({
  289. type: 'error',
  290. message: this.$t('submittedFailed')
  291. });
  292. });
  293. }).catch(() => { });
  294. },
  295. offShelfPrev(data) {
  296. this.$confirm(this.$t('resourcesManagement.offShelfConfirm'), this.$t('tips'), {
  297. confirmButtonText: this.$t('confirm1'),
  298. cancelButtonText: this.$t('cancel'),
  299. type: 'warning',
  300. lockScroll: false,
  301. }).then(() => {
  302. this.offShelfDialogData = data;
  303. getResSpecificationScenes({ ID: data.ID }).then(res => {
  304. res = res.data;
  305. if (res.Code === 0) {
  306. if (res.Data.List.length) {
  307. this.offShelfDialogShow = true;
  308. this.offSelfDialogContent = res.Data.List.map((item) => `[${item.ID}]${item.SceneName}`).join(', ');
  309. } else {
  310. this.offShelf();
  311. }
  312. } else {
  313. console.log(res);
  314. }
  315. }).catch(err => {
  316. console.log(err);
  317. });
  318. }).catch(() => { });
  319. },
  320. offShelf() {
  321. updateResSpecification({
  322. ID: this.offShelfDialogData.ID,
  323. action: 'off-shelf'
  324. }).then(res => {
  325. res = res.data;
  326. if (res.Code === 0) {
  327. this.$message({
  328. type: 'success',
  329. message: this.$t('submittedSuccessfully')
  330. });
  331. this.offShelfDialogShow = false;
  332. this.getTableData();
  333. } else {
  334. this.$message({
  335. type: 'error',
  336. message: this.$t('submittedFailed')
  337. });
  338. }
  339. }).catch(err => {
  340. console.log(err);
  341. this.$message({
  342. type: 'error',
  343. message: this.$t('submittedFailed')
  344. });
  345. });
  346. },
  347. },
  348. mounted: function () {
  349. this.getQueueList();
  350. this.getTableData();
  351. },
  352. beforeDestroy: function () {
  353. },
  354. };
  355. </script>
  356. <style scoped lang="less">
  357. .title {
  358. height: 30px;
  359. display: flex;
  360. align-items: center;
  361. margin-bottom: 5px;
  362. span {
  363. font-weight: 700;
  364. font-size: 16px;
  365. color: rgb(16, 16, 16);
  366. }
  367. }
  368. .tools-bar {
  369. display: flex;
  370. align-items: center;
  371. justify-content: space-between;
  372. margin-bottom: 10px;
  373. .select {
  374. margin-right: 10px;
  375. /deep/ .el-input__inner {
  376. border-radius: 0;
  377. }
  378. }
  379. }
  380. .table-container {
  381. margin-bottom: 16px;
  382. /deep/ .el-table__header {
  383. th {
  384. background: rgb(245, 245, 246);
  385. font-size: 12px;
  386. color: rgb(36, 36, 36);
  387. }
  388. }
  389. /deep/ .el-table__body {
  390. td {
  391. font-size: 12px;
  392. }
  393. }
  394. .op-btn {
  395. cursor: pointer;
  396. font-size: 12px;
  397. color: rgb(25, 103, 252);
  398. margin-right: 4px;
  399. }
  400. }
  401. .center {
  402. display: flex;
  403. justify-content: center;
  404. }
  405. .form {
  406. margin: 5px 0 5px 0;
  407. display: flex;
  408. justify-content: center;
  409. flex-direction: column;
  410. align-items: center;
  411. }
  412. .form-row {
  413. display: flex;
  414. min-height: 42px;
  415. margin-bottom: 4px;
  416. .content {
  417. width: 500px;
  418. display: flex;
  419. align-items: center;
  420. }
  421. }
  422. .btn {
  423. color: rgb(2, 0, 4);
  424. background-color: rgb(194, 199, 204);
  425. border-color: rgb(194, 199, 204);
  426. &.confirm-btn {
  427. color: #fff;
  428. background-color: rgb(56, 158, 13);
  429. border-color: rgb(56, 158, 13);
  430. }
  431. }
  432. </style>