RepoAuth.vue 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353
  1. <template>
  2. <el-container>
  3. <el-header height="220">
  4. <h3>仓库认证列表</h3>
  5. <el-row style="margin-top: 10px">
  6. <el-button type="success" size="mini" icon="el-icon-plus" @click="handleShowAdd">添加</el-button>
  7. </el-row>
  8. </el-header>
  9. <el-main>
  10. <el-table
  11. :data="dataList"
  12. border
  13. height="480"
  14. style="width: 100%"
  15. >
  16. <el-table-column
  17. prop="authType"
  18. label="认证类型"
  19. />
  20. <el-table-column
  21. prop="name"
  22. label="认证名字"
  23. />
  24. <el-table-column
  25. prop="type"
  26. label="仓库类型"
  27. />
  28. <el-table-column
  29. prop="username"
  30. label="帐号"
  31. />
  32. <el-table-column
  33. prop="password"
  34. label="密码"
  35. />
  36. <el-table-column
  37. prop="useCount"
  38. label="使用量"
  39. >
  40. <template slot-scope="scope">
  41. <el-tag disable-transitions>
  42. <span>{{ scope.row.useCount }}</span>
  43. </el-tag>
  44. <el-button
  45. style="margin-top: 5px; margin-left: 5px"
  46. size="mini"
  47. type="success"
  48. @click="handleUsage(scope.row)"
  49. >查看</el-button>
  50. </template>
  51. </el-table-column>
  52. <el-table-column
  53. fixed="right"
  54. label="操作"
  55. width="120"
  56. >
  57. <template slot-scope="scope">
  58. <el-button
  59. size="mini"
  60. type="danger"
  61. @click="handleEdit(scope.$index, scope.row)"
  62. >删除</el-button>
  63. </template>
  64. </el-table-column>
  65. </el-table>
  66. <el-pagination
  67. background
  68. :small="screenWidth <= 768"
  69. layout="prev, pager, next"
  70. :page-size="pageSize"
  71. :current-page="currentPage"
  72. :total="totalSize"
  73. @current-change="handleCurrentChange"
  74. @prev-click="handleCurrentChange"
  75. @next-click="handleCurrentChange"
  76. />
  77. </el-main>
  78. <!-- 添加编译器对话框 -->
  79. <el-dialog
  80. title="添加仓库认证"
  81. append-to-body
  82. :visible.sync="showAddDialog"
  83. center
  84. >
  85. <div class="compiler-config-steps">
  86. <el-steps :active="active" finish-status="success" simple style="margin-bottom: 30px">
  87. <el-step title="基础配置" icon="el-icon-monitor" />
  88. <el-step title="认证配置" icon="el-icon-edit" />
  89. </el-steps>
  90. <el-form ref="form" :model="form" :rules="dynamicRules" label-width="130px">
  91. <div v-show="active === 0">
  92. <el-form-item label="认证类型" prop="authType">
  93. <el-select v-model="form.authType" placeholder="请选择认证类型" style="width: 100%">
  94. <el-option
  95. v-for="(item, index) in authTypes"
  96. :key="index"
  97. :label="item.label"
  98. :value="item.value"
  99. />
  100. </el-select>
  101. </el-form-item>
  102. <el-form-item label="认证名称" prop="name">
  103. <el-input v-model="form.name" placeholder="例如 git-auth" />
  104. </el-form-item>
  105. <el-form-item label="仓库类型" prop="type">
  106. <el-select v-model="form.type" placeholder="请选择仓库类型" style="width: 100%">
  107. <el-option
  108. v-for="(item, index) in repoTypes"
  109. :key="index"
  110. :label="item.label"
  111. :value="item.value"
  112. />
  113. </el-select>
  114. </el-form-item>
  115. </div>
  116. <div v-show="active === 1">
  117. <div v-if="form.authType === 'ssh'">
  118. <el-form-item label="RSA 私钥" prop="rsaPrikey">
  119. <el-input
  120. v-model="form.rsaPrikey"
  121. type="textarea"
  122. :autosize="{ minRows: 4 }"
  123. placeholder="请填写 RSA 私钥"
  124. />
  125. </el-form-item>
  126. </div>
  127. <div v-else-if="form.authType === 'http'">
  128. <el-form-item label="用户名" prop="username">
  129. <el-input v-model="form.username" placeholder="请填写用户名" />
  130. </el-form-item>
  131. <el-form-item label="密码" prop="password">
  132. <el-input v-model="form.password" placeholder="请填写密码" />
  133. </el-form-item>
  134. </div>
  135. <div v-else>
  136. <el-input value="none 认证类型不需要填写任何认证资料" readonly />
  137. </div>
  138. </div>
  139. <el-form-item style="margin-top: 40px">
  140. <el-button v-if="active > 0" @click="active--">上一步</el-button>
  141. <el-button v-if="active < 1" type="primary" @click="nextStep">下一步</el-button>
  142. <el-button v-if="active === 1" type="success" @click="onAddRepoAuth">提交保存</el-button>
  143. </el-form-item>
  144. </el-form>
  145. </div>
  146. </el-dialog>
  147. </el-container>
  148. </template>
  149. <script>
  150. import { addRepoAuth, deleteRepoAuth, getRepoAuthList, getRepoTypes } from '@/api/devops'
  151. export default {
  152. name: 'RepoAuth',
  153. data() {
  154. return {
  155. queryInfo: {
  156. scope: null,
  157. pn: 1
  158. },
  159. // 屏幕宽度, 为了控制分页条的大小
  160. screenWidth: document.body.clientWidth,
  161. currentPage: 1,
  162. pageSize: 10,
  163. totalSize: 0,
  164. dataList: [],
  165. // **********************************************************************
  166. showAddDialog: false,
  167. active: 0,
  168. form: {
  169. authType: 'http',
  170. name: '',
  171. type: 'git',
  172. username: '',
  173. password: '',
  174. rsaPrikey: ''
  175. },
  176. repoTypes: [],
  177. authTypes: []
  178. }
  179. },
  180. computed: {
  181. dynamicRules() {
  182. const baseRules = {
  183. type: [{ required: true, message: '请选择仓库类型', trigger: 'blur' }],
  184. name: [{ required: true, message: '请输入名称', trigger: 'blur' }],
  185. authType: [{ required: true, message: '请选择认证类型', trigger: 'blur' }]
  186. }
  187. // 根据选择的类型增加特定规则
  188. if (this.form.authType === 'ssh') {
  189. baseRules.rsaPrikey = [{ required: true, message: 'ssh 认证类型必须填写 RSA 私钥', trigger: 'blur' }]
  190. } else if (this.form.authType === 'http') {
  191. baseRules.username = [{ required: true, message: 'http 认证类型必须填写 username', trigger: 'blur' }]
  192. baseRules.password = [{ required: true, message: 'http 认证类型必须填写 password', trigger: 'blur' }]
  193. }
  194. return baseRules
  195. }
  196. },
  197. created() {
  198. document.title = '仓库认证列表'
  199. this.getData()
  200. },
  201. methods: {
  202. handleCurrentChange(pageNumber) {
  203. this.currentPage = pageNumber
  204. this.getData()
  205. // 回到顶部
  206. scrollTo(0, 0)
  207. },
  208. getData() {
  209. this.dataList = []
  210. getRepoAuthList(this.currentPage).then(resp => {
  211. if (resp.code === 0) {
  212. const respData = resp.data
  213. this.dataList = respData.list
  214. this.totalSize = respData.totalSize
  215. } else {
  216. this.$message.error(resp.msg)
  217. }
  218. }).catch(error => {
  219. this.$message.error(error.message)
  220. })
  221. },
  222. handleShowAdd(index, row) {
  223. getRepoTypes().then(resp => {
  224. if (resp.code === 0) {
  225. this.repoTypes = resp.data.repoTypes
  226. this.authTypes = resp.data.authTypes
  227. this.showAddDialog = true
  228. } else {
  229. this.$message.error(resp.msg)
  230. }
  231. }).catch(error => {
  232. this.$message.error(error.message)
  233. })
  234. },
  235. onAddRepoAuth1() {
  236. const formData = new FormData()
  237. formData.append('type', this.form.type)
  238. formData.append('name', this.form.name)
  239. formData.append('authType', this.form.authType)
  240. formData.append('username', this.form.username)
  241. formData.append('password', this.form.password)
  242. addRepoAuth(formData).then(resp => {
  243. this.$message.info(resp.msg)
  244. this.getData()
  245. }).catch(error => {
  246. this.$message.error(error.message)
  247. }).finally(() => {
  248. this.showAddDialog = false
  249. })
  250. },
  251. // 异步校验并跳转
  252. async nextStep() {
  253. const stepFields = ['type', 'authType', 'name'] // 第一步需要校验的字段
  254. try {
  255. // 关键:将所有字段的校验转为 Promise 数组
  256. const checkActions = stepFields.map(field => {
  257. return new Promise((resolve, reject) => {
  258. this.$refs.form.validateField(field, error => {
  259. if (error) reject(error)
  260. else resolve()
  261. })
  262. })
  263. })
  264. await Promise.all(checkActions)
  265. this.active++ // 只有全部校验成功才加 1
  266. } catch (e) {
  267. this.$message.warning('请检查基础配置是否填写完整')
  268. }
  269. },
  270. onAddRepoAuth() {
  271. this.$refs.form.validate((valid) => {
  272. if (valid) {
  273. addRepoAuth(this.form).then(resp => {
  274. this.$message.info(resp.msg)
  275. this.$refs.form.resetFields();
  276. this.getData()
  277. }).catch(error => {
  278. this.$message.error(error.message)
  279. }).finally(() => {
  280. this.showAddDialog = false
  281. })
  282. } else {
  283. return false
  284. }
  285. })
  286. },
  287. handleEdit(index, row) {
  288. this.$confirm('确定要删除 ' + row.name + '?', '提示', {
  289. confirmButtonText: '确定',
  290. cancelButtonText: '取消',
  291. type: 'warning'
  292. }).then(() => {
  293. const formData = new FormData()
  294. formData.append('id', row.id)
  295. deleteRepoAuth(formData).then(resp => {
  296. this.$message.info(resp.msg)
  297. this.getData()
  298. }).catch(error => {
  299. this.$message.error(error.message)
  300. })
  301. }).catch(() => {
  302. this.$message({
  303. type: 'info',
  304. message: '已取消'
  305. })
  306. })
  307. },
  308. handleUsage(row) {
  309. this.$message.info('handleUsage')
  310. }
  311. }
  312. }
  313. </script>
  314. <style scoped>
  315. .compiler-config-steps {
  316. max-width: 800px;
  317. margin: 0 auto;
  318. padding: 20px;
  319. background: #fff;
  320. border-radius: 8px;
  321. }
  322. .form-tip {
  323. font-size: 12px;
  324. color: #909399;
  325. line-height: 2;
  326. }
  327. /* 使用 ::v-deep 穿透 scoped 限制
  328. 这是 Vue 2 中兼容性最好的写法,支持 Less/Sass
  329. */
  330. ::v-deep .el-textarea__inner {
  331. font-family: 'Courier New', Courier, monospace;
  332. background-color: #f8f9fa;
  333. color: #2c3e50;
  334. border: 1px solid #dcdfe6;
  335. }
  336. /* 鼠标悬停和聚焦时的效果优化 */
  337. ::v-deep .el-textarea__inner:focus {
  338. background-color: #fff;
  339. border-color: #409EFF;
  340. }
  341. </style>