RepoAuth.vue 9.9 KB

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