EditAttributes.vue 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431
  1. <template>
  2. <base-dialog @cancel="cancelDialog">
  3. <div slot="header">{{$t('compute.text_247')}}</div>
  4. <div slot="body">
  5. <a-form v-bind="formItemLayout" :form="form.fc">
  6. <a-form-item :label="$t('compute.text_228')" v-bind="formItemLayout">
  7. <a-input v-decorator="decorators.name" :plcaeholder="$t('compute.text_627')" />
  8. </a-form-item>
  9. <!-- <a-form-item :label="$t('common.text00076')" v-bind="formItemLayout">
  10. <a-radio-group v-decorator="decorators.protected">
  11. <a-radio-button value="true">{{$t('compute.text_656')}}</a-radio-button>
  12. <a-radio-button value="false">{{$t('compute.text_569')}}</a-radio-button>
  13. </a-radio-group>
  14. </a-form-item>-->
  15. <a-form-item :label="$t('compute.text_1365')">
  16. <os-arch v-on:change="osArchChangeHandle" v-decorator="decorators.os_arch" :form="form" />
  17. </a-form-item>
  18. <a-form-item :label="$t('compute.text_267')" v-bind="formItemLayout" v-if="!$route.path.includes('app-package')">
  19. <a-radio-group @change="osTypeChangeHandle" v-decorator="decorators.osType">
  20. <a-radio-button value="Linux">Linux</a-radio-button>
  21. <a-radio-button value="Windows">Windows</a-radio-button>
  22. <a-radio-button value="Other">{{$t('compute.text_151')}}</a-radio-button>
  23. </a-radio-group>
  24. </a-form-item>
  25. <a-form-item :label="$t('compute.text_657')" v-bind="formItemLayout" v-if="!$route.path.includes('app-package')">
  26. <a-select
  27. :placeholder="$t('compute.text_658')"
  28. v-decorator="decorators.osDistribution"
  29. @change="osDistributionChange">
  30. <a-select-option
  31. v-for="item in osNewDisOptions"
  32. :key="item.value"
  33. :value="item.value">{{item.text}}</a-select-option>
  34. </a-select>
  35. <a-input
  36. v-if="isDisOther"
  37. v-decorator="decorators.osOtherDistribution"
  38. :placeholder="$t('compute.text_659')" />
  39. </a-form-item>
  40. <a-form-item
  41. :label="$t('compute.text_633')"
  42. :extra="$t('compute.image.min_disk.extra')"
  43. v-bind="formItemLayout"
  44. v-if="!isHostImage">
  45. <a-input-number
  46. :min="1"
  47. :max="1000"
  48. :step="50"
  49. :precision="0"
  50. v-decorator="decorators.minDisk" />GB
  51. </a-form-item>
  52. <a-form-item :label="$t('compute.text_634')" v-bind="formItemLayout">
  53. <a-radio-group v-decorator="decorators.diskDriver">
  54. <a-radio-button
  55. v-for="(item, index) in diskDriverOptions"
  56. :value="item.value"
  57. :key="index">{{item.text}}</a-radio-button>
  58. </a-radio-group>
  59. </a-form-item>
  60. <a-form-item :label="$t('compute.text_635')" v-bind="formItemLayout">
  61. <a-radio-group v-decorator="decorators.netDriver">
  62. <a-radio-button
  63. v-for="(item, index) in netDriverOptions"
  64. :value="item.value"
  65. :key="index">{{item.text}}</a-radio-button>
  66. </a-radio-group>
  67. </a-form-item>
  68. <a-form-item :label="$t('compute.text_1155')">
  69. <a-radio-group v-decorator="decorators.bios">
  70. <a-radio-button
  71. v-for="(item, index) in biosOptions"
  72. :value="item.value"
  73. :key="index"
  74. :disabled="isArm && item.value==='BIOS'">{{item.text}}</a-radio-button>
  75. </a-radio-group>
  76. </a-form-item>
  77. <a-form-item :label="$t('compute.vdi_protocol')">
  78. <a-radio-group v-decorator="decorators.vdi">
  79. <a-radio-button
  80. v-for="(item, index) in vdiOptions"
  81. :value="item.value"
  82. :key="index">{{item.text}}</a-radio-button>
  83. </a-radio-group>
  84. </a-form-item>
  85. </a-form>
  86. </div>
  87. <div slot="footer">
  88. <a-button type="primary" @click="handleConfirm" :loading="loading">{{ $t('dialog.ok') }}</a-button>
  89. <a-button @click="cancelDialog">{{ $t('dialog.cancel') }}</a-button>
  90. </div>
  91. </base-dialog>
  92. </template>
  93. <script>
  94. import * as R from 'ramda'
  95. import DialogMixin from '@/mixins/dialog'
  96. import WindowsMixin from '@/mixins/windows'
  97. import OsArch from '@/sections/OsArch'
  98. import { HOST_CPU_ARCHS } from '@/constants/compute'
  99. export default {
  100. name: 'ImageEditAttributesDialog',
  101. components: {
  102. OsArch,
  103. },
  104. mixins: [DialogMixin, WindowsMixin],
  105. data () {
  106. const data = this.params.data[0]
  107. let os_arch = data.os_arch || HOST_CPU_ARCHS.x86.key
  108. if (data.properties && data.properties.os_arch) {
  109. os_arch = data.properties.os_arch.includes('x86') ? HOST_CPU_ARCHS.x86.key : HOST_CPU_ARCHS.arm.key
  110. }
  111. let bios = 'BIOS'
  112. const { properties = {} } = data
  113. const { uefi_support, bios_support } = properties
  114. if (uefi_support === 'true' && bios_support === 'true') {
  115. bios = 'BIOS & UEFI'
  116. } else if (uefi_support === 'true' && bios_support !== 'true') {
  117. bios = 'UEFI'
  118. } else if (uefi_support !== 'true') {
  119. bios = 'BIOS'
  120. }
  121. const isArm = (os_arch === HOST_CPU_ARCHS.arm.key)
  122. return {
  123. isArm: isArm,
  124. loading: false,
  125. form: {
  126. fc: this.$form.createForm(this),
  127. },
  128. decorators: {
  129. name: [
  130. 'name',
  131. {
  132. initialValue: this.params.data[0].name,
  133. validateFirst: true,
  134. rules: [
  135. { required: true, message: this.$t('compute.text_660') },
  136. { validator: this.$validate('imageName') },
  137. { validator: this.checkTemplateName },
  138. ],
  139. },
  140. ],
  141. protected: [
  142. 'protected',
  143. {
  144. initialValue: 'true',
  145. },
  146. ],
  147. osType: [
  148. 'osType',
  149. {
  150. initialValue: 'Linux',
  151. },
  152. ],
  153. osDistribution: [
  154. 'osDistribution',
  155. {
  156. initialValue: 'CentOS',
  157. },
  158. ],
  159. osOtherDistribution: [
  160. 'osOtherDistribution',
  161. ],
  162. minDisk: [
  163. 'minDisk',
  164. {
  165. initialValue: 1,
  166. },
  167. ],
  168. diskDriver: [
  169. 'diskDriver',
  170. ],
  171. netDriver: [
  172. 'netDriver',
  173. ],
  174. os_arch: [
  175. 'os_arch',
  176. {
  177. initialValue: os_arch,
  178. },
  179. ],
  180. bios: [
  181. 'bios',
  182. {
  183. initialValue: bios,
  184. },
  185. ],
  186. vdi: [
  187. 'vdi',
  188. {
  189. initialValue: 'vnc',
  190. },
  191. ],
  192. },
  193. formItemLayout: {
  194. wrapperCol: {
  195. span: 17,
  196. },
  197. labelCol: {
  198. span: 7,
  199. },
  200. },
  201. osDistributionOptions: {
  202. Windows: [
  203. { text: 'Windows Server 2025', value: 'Windows Server 2025' },
  204. { text: 'Windows Server 2022', value: 'Windows Server 2022' },
  205. { text: 'Windows Server 2019', value: 'Windows Server 2019' },
  206. { text: 'Windows Server 2016', value: 'Windows Server 2016' },
  207. { text: 'Windows Server 2012 R2', value: 'Windows Server 2012 R2' },
  208. { text: 'Windows Server 2012', value: 'Windows Server 2012' },
  209. { text: 'Windows Server 2008 R2', value: 'Windows Server 2008 R2' },
  210. { text: 'Windows Server 2008', value: 'Windows Server 2008' },
  211. { text: 'Windows 11', value: 'Windows 11' },
  212. { text: 'Windows 10', value: 'Windows 10' },
  213. { text: this.$t('compute.text_151'), value: 'Other' },
  214. ],
  215. Linux: [
  216. { text: 'CentOS', value: 'CentOS' },
  217. { text: 'CoreOS', value: 'CoreOS' },
  218. { text: 'Debian', value: 'Debian' },
  219. { text: 'Fedora', value: 'Fedora' },
  220. { text: 'Gentoo', value: 'Gentoo' },
  221. { text: 'OpenSUSE', value: 'OpenSUSE' },
  222. { text: 'RedHat', value: 'RedHat' },
  223. { text: 'SUSE Linux', value: 'SUSE Linux' },
  224. { text: 'Ubuntu', value: 'Ubuntu' },
  225. { text: 'Anolis', value: 'Anolis' },
  226. { text: 'Rocky Linux', value: 'Rocky' },
  227. { text: this.$t('compute.os.kylin'), value: 'Kylin' },
  228. { text: this.$t('compute.os.nfs'), value: 'nfs' },
  229. { text: this.$t('compute.text_151'), value: 'Other' },
  230. ],
  231. Other: [
  232. { text: this.$t('compute.text_151'), value: 'Other' },
  233. ],
  234. },
  235. osNewDisOptions: [
  236. { text: 'CentOS', value: 'CentOS' },
  237. { text: 'CoreOS', value: 'CoreOS' },
  238. { text: 'Debian', value: 'Debian' },
  239. { text: 'Fedora', value: 'Fedora' },
  240. { text: 'Gentoo', value: 'Gentoo' },
  241. { text: 'OpenSUSE', value: 'OpenSUSE' },
  242. { text: 'RedHat', value: 'RedHat' },
  243. { text: 'SUSE Linux', value: 'SUSE Linux' },
  244. { text: 'Ubuntu', value: 'Ubuntu' },
  245. { text: 'OpenKylin', value: 'OpenKylin' },
  246. { text: 'OpenCloudOS', value: 'OpenCloudOS' },
  247. { text: 'AlmaLinux', value: 'AlmaLinux' },
  248. { text: 'UOSDesktop', value: 'UOSDesktop' },
  249. { text: 'OpenEuler', value: 'OpenEuler' },
  250. { text: 'Anolis', value: 'Anolis' },
  251. { text: 'Rocky Linux', value: 'Rocky' },
  252. { text: this.$t('compute.os.kylin'), value: 'Kylin' },
  253. { text: this.$t('compute.os.neokylin'), value: 'NeoKylin' },
  254. { text: this.$t('compute.os.nfs'), value: 'nfs' },
  255. { text: this.$t('compute.text_151'), value: 'Other' },
  256. ],
  257. isDisOther: false,
  258. initName: '',
  259. diskDriverOptions: [
  260. { text: this.$t('compute.text_661'), value: '' },
  261. { text: 'virtio', value: 'virtio' },
  262. { text: 'scsi', value: 'scsi' },
  263. { text: 'pvscsi', value: 'pvscsi' },
  264. { text: 'ide', value: 'ide' },
  265. { text: 'sata', value: 'sata' },
  266. ],
  267. netDriverOptions: [
  268. { text: this.$t('compute.text_661'), value: '' },
  269. { text: 'virtio', value: 'virtio' },
  270. { text: 'e1000', value: 'e1000' },
  271. { text: 'vmxnet3', value: 'vmxnet3' },
  272. ],
  273. biosOptions: [
  274. { text: 'BIOS', value: 'BIOS' },
  275. { text: 'UEFI', value: 'UEFI' },
  276. { text: 'BIOS & UEFI', value: 'BIOS & UEFI' },
  277. ],
  278. vdiOptions: [
  279. { text: this.$t('compute.text_661'), value: '' },
  280. { text: 'vnc', value: 'vnc' },
  281. { text: 'spice', value: 'spice' },
  282. ],
  283. initMinDisk: 0,
  284. }
  285. },
  286. computed: {
  287. isHostImage () {
  288. return this.params.data[0].root_image
  289. },
  290. },
  291. created () {
  292. this.fetchData()
  293. },
  294. methods: {
  295. fetchData () {
  296. this.manager = new this.$Manager(this.isHostImage ? 'guestimages' : 'images', 'v1')
  297. this.manager.get({ id: this.params.data[0].id })
  298. .then((res) => {
  299. const { name, min_disk: minDisk } = res.data
  300. const { os_type: osType, os_distribution: osDistribution, disk_driver: diskDriver, net_driver: netDriver, uefi_support: uefiSupport, bios_support: biosSupport, vdi_protocol: vdiProtocol } = res.data.properties
  301. this.initName = name
  302. this.initMinDisk = minDisk
  303. this.$nextTick(() => {
  304. this.form.fc.setFieldsValue({
  305. name,
  306. minDisk: Math.round(minDisk / 1024),
  307. protected: res.data.protected + '',
  308. osType,
  309. osDistribution,
  310. diskDriver: diskDriver || '',
  311. netDriver: netDriver || '',
  312. bios: this.getBios(uefiSupport, biosSupport),
  313. vdi: vdiProtocol || 'vnc',
  314. })
  315. })
  316. })
  317. },
  318. getBios (uefiSupport, biosSupport) {
  319. if (uefiSupport === 'true' && biosSupport === 'true') {
  320. return 'BIOS & UEFI'
  321. } else if (uefiSupport === 'true' && biosSupport !== 'true') {
  322. return 'UEFI'
  323. }
  324. return 'BIOS'
  325. },
  326. checkTemplateName (rule, value, callback) {
  327. return new this.$Manager(this.isHostImage ? 'guestimages' : 'images', 'v1').list({
  328. params: {
  329. name: value,
  330. },
  331. }).then(res => {
  332. const data = res.data.data
  333. if (!R.isNil(data) && !R.isEmpty(data)) {
  334. if (data[0].name === this.initName) {
  335. callback()
  336. } else {
  337. callback(new Error(this.$t('compute.text_662')))
  338. }
  339. } else {
  340. callback()
  341. }
  342. })
  343. },
  344. osArchChangeHandle (e) {
  345. this.isArm = (e === HOST_CPU_ARCHS.arm.key)
  346. this.$nextTick(() => {
  347. this.form.fc.setFieldsValue({ bios: 'UEFI' })
  348. })
  349. },
  350. osTypeChangeHandle (e) {
  351. const v = e.target.value
  352. this.osNewDisOptions = this.osDistributionOptions[v]
  353. if (v === 'Other') {
  354. this.form.fc.setFieldsValue({ osDistribution: 'Other' })
  355. this.isDisOther = true
  356. } else {
  357. this.form.fc.setFieldsValue({ osDistribution: this.osNewDisOptions[0].value })
  358. this.isDisOther = false
  359. this.osDistributionChange(this.osNewDisOptions[0].value)
  360. }
  361. },
  362. osDistributionChange (e) {
  363. if (e === 'Other') {
  364. this.isDisOther = true
  365. } else {
  366. this.isDisOther = false
  367. if (e.startsWith('Windows')) {
  368. let minDisk = 40
  369. if (e === 'Windows 11') {
  370. minDisk = 60
  371. }
  372. if (this.form.fc.getFieldValue('minDisk') < minDisk) {
  373. this.form.fc.setFieldsValue({ minDisk: minDisk })
  374. }
  375. }
  376. }
  377. },
  378. doEdit (data) {
  379. return new this.$Manager(this.isHostImage ? 'guestimages' : 'images', 'v1').update({
  380. id: this.params.data[0].id,
  381. data,
  382. })
  383. },
  384. async handleConfirm () {
  385. this.loading = true
  386. try {
  387. const values = await this.form.fc.validateFields()
  388. const { name, osType, osDistribution, osOtherDistribution, minDisk, diskDriver, netDriver, os_arch, bios, vdi } = values
  389. const params = {
  390. name,
  391. // protected: values.protected,
  392. os_arch,
  393. properties: {
  394. os_type: osType,
  395. os_distribution: this.isDisOther ? osOtherDistribution : osDistribution,
  396. disk_driver: diskDriver,
  397. net_driver: netDriver,
  398. os_arch,
  399. vdi_protocol: vdi,
  400. },
  401. }
  402. if (!this.isHostImage) {
  403. params['min-disk'] = minDisk * 1024
  404. if (params['min-disk'] === 0) { // 说明上传了一个小于1G的镜像,被四舍五入成0了,要取源数据
  405. params['min-disk'] = this.initMinDisk
  406. }
  407. }
  408. if (bios === 'UEFI') {
  409. params.properties.uefi_support = 'true'
  410. params.properties.bios_support = 'false'
  411. } else if (bios === 'BIOS') {
  412. params.properties.uefi_support = 'false'
  413. params.properties.bios_support = 'true'
  414. } else if (bios === 'BIOS & UEFI') {
  415. params.properties.uefi_support = 'true'
  416. params.properties.bios_support = 'true'
  417. }
  418. await this.doEdit(params)
  419. this.loading = false
  420. this.cancelDialog()
  421. this.params.refresh()
  422. } catch (error) {
  423. this.loading = false
  424. throw error
  425. }
  426. },
  427. },
  428. }
  429. </script>