| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308 |
- <template>
- <div>
- <a-alert type="warning" v-if="isCE || $store.getters.isSysCE">
- <span slot="message">{{ $t('common.image_url_tip') }} <a href="https://www.cloudpods.org/docs/guides/onpremise/glance/common-image-url" target="_blank">{{ $t('common.normal_open_image') }}</a></span>
- </a-alert>
- <a-alert type="warning" v-else>
- <span slot="message">{{ $t('common.image_url_tip2') }}</span>
- </a-alert>
- <page-header :title="$t('compute.open_image_market')" />
- <a-form-model class="mt-3 mb-2" v-bind="layout">
- <a-form-model-item>
- <a-radio-group v-model="form.os_arch">
- <a-radio-button v-for="(item, index) in archList" :key="index" :value="item.value">{{ item.label }}</a-radio-button>
- </a-radio-group>
- </a-form-model-item>
- <a-form-model-item>
- <a-radio-group v-model="form.source">
- <a-radio-button v-for="(item, index) in sourceList" :key="index" :value="item.value">{{ item.label }}</a-radio-button>
- </a-radio-group>
- </a-form-model-item>
- <a-form-model-item>
- <a-radio-group v-model="form.distribution" size="large">
- <a-radio-button v-for="(item, index) in distributionList" :key="index" :value="item.value" style="width:60px;height:60px;text-align:center;line-height:60px;vertical-align:middle;padding:0;"><img v-if="item.os" :src="item.os" style="height:40px;" /></a-radio-button>
- </a-radio-group>
- </a-form-model-item>
- </a-form-model>
- <page-card-list
- :list="list"
- :card-fields="cardFields"
- :showPageer="false"
- :isRefreshed="false"
- :singleActions="singleActions" />
- </div>
- </template>
- <script>
- import { mapGetters } from 'vuex'
- import axios from 'axios'
- import WindowsMixin from '@/mixins/windows'
- import { isCE } from '@/utils/utils'
- const path = require('path')
- const imagesLogoFiles = require.context('@/assets/images/os-images', false, /.svg$/)
- const imagesLogos = []
- imagesLogoFiles.keys().forEach(key => {
- const name = path.basename(key, '.svg') // 返回文件名 不含后缀名
- imagesLogos.push(name)
- })
- const fileUrl = 'https://www.cloudpods.org/openimages.yaml'
- const attributes = ['distribution', 'os_name', 'os_arch', 'os_version', 'build', 'source', 'url']
- export default {
- name: 'ImageMarket',
- mixins: [WindowsMixin],
- data () {
- return {
- loading: false,
- imageList: [],
- cardFields: {
- url: 'os',
- title: 'title',
- description: 'os_name',
- desc: 'desc',
- },
- list: {
- data: [],
- loading: false,
- },
- layout: {
- wrapperCol: {
- span: 20,
- },
- labelCol: {
- span: 4,
- },
- },
- singleActions: [
- {
- label: this.$t('compute.text_679'),
- action: async (data) => {
- try {
- await new this.$Manager('images', 'v2').create({
- data: {
- domain_id: this.userInfo.projectDomainId,
- project_id: this.userInfo.projectId,
- copy_from: data.url,
- name: data.name,
- os_arch: data.os_arch,
- properties: {
- os_type: data.os_name,
- os_version: data.os_version,
- os_arch: data.os_arch,
- },
- },
- })
- this.$message.success(this.$t('compute.text_423'))
- this.$router.push({ name: 'Image' })
- } catch (error) {
- throw error
- }
- },
- meta: (obj) => {
- return {
- buttonType: 'primary',
- }
- },
- },
- ],
- imagesLogos,
- form: {
- os_arch: 'x86_64',
- source: 'all',
- distribution: 'Debian',
- },
- }
- },
- computed: {
- ...mapGetters(['userInfo']),
- archList () {
- const ret = []
- this.imageList.map(item => {
- if (item.data.os_arch && !ret.some(l => l.value === item.data.os_arch)) {
- ret.push({ value: item.data.os_arch, label: item.data.os_arch })
- }
- })
- return ret
- },
- distributionList () {
- const ret = []
- this.imageList.map(item => {
- if (item.data.os_arch === this.form.os_arch && item.data.source_type.includes(this.form.source) && item.data.distribution && !ret.some(l => l.value === item.data.distribution)) {
- ret.push({ value: item.data.distribution, label: item.data.distribution, os: item.data.os })
- }
- })
- return ret
- },
- isce () {
- return isCE()
- },
- sourceList () {
- return [
- { value: 'all', label: this.$t('compute.image_source_global') },
- { value: 'cn', label: this.$t('compute.image_source_cn') },
- { value: 'ov', label: this.$t('compute.image_source_ov') },
- ]
- },
- },
- watch: {
- form: {
- handler (val) {
- this.initList()
- },
- deep: true,
- },
- distributionList (val) {
- if (val.length) {
- if (!val.some(item => item.value === this.form.distribution)) {
- this.form.distribution = val[0].value
- }
- }
- },
- },
- created () {
- this.fetchData()
- },
- methods: {
- parseImageOption (str) {
- let key = ''
- let value = ''
- attributes.map(field => {
- const fieldStart = field + ': '
- if (str.startsWith(fieldStart)) {
- key = field
- value = str.substring(fieldStart.length)
- }
- })
- return { key, value }
- },
- parseImageData (str) {
- const list = str.split('- distribution:')
- const imageList = []
- list.map((str, index) => {
- if (index !== 0) {
- const obj = {}
- const originStr = 'distribution:' + str
- const optsList = originStr.split('\n').filter(item => item.trim() !== '').map(item => item.trim())
- optsList.map(item => {
- const { key, value } = this.parseImageOption(item)
- obj[key] = value
- })
- imageList.push({ ...obj, id: imageList.length + 1 })
- }
- })
- return imageList
- },
- handleFilterChange (filter) {
- const keys = Object.keys(filter)
- this.list.responseData = {
- data: this.imageList.filter(item => {
- return keys.every(key => {
- return item[key] && item[key].toLowerCase().includes(filter[key][0].toLowerCase())
- })
- }),
- }
- this.selectedImages = []
- this.list.fetchData()
- },
- handleSelected (selected) {
- this.selectedImages = selected
- },
- getOsName (item) {
- let ret = ''
- const os_name = (item.distribution || '').toLowerCase()
- ret = this.imagesLogos.includes(os_name) ? os_name : ''
- if (!ret && os_name.includes('ubuntu')) {
- ret = 'ubuntu'
- }
- if (!ret && os_name.includes('anolis')) {
- ret = 'anolis'
- }
- return ret || 'unknow'
- },
- fetchData () {
- this.list.loading = true
- axios.get(fileUrl).then(res => {
- const { data = '' } = res
- this.imageList = this.parseImageData(data).map(item => {
- const ret = { data: { ...item } }
- ret.data.title = `${item.distribution} ${item.os_version}`
- ret.data.desc = this.$t('compute.image_market.desc', [item.os_arch, item.source, item.build || '-'])
- ret.data.name = `${item.distribution}-${item.os_name}-${item.os_version}-${item.os_arch}`
- if (item.build) {
- ret.data.name += `-${item.build}`
- }
- const os_name = this.getOsName(item)
- ret.data.os = require(`@/assets/images/os-images/${this.imagesLogos.includes(os_name) ? os_name : 'unknow'}.svg`) || ''
- ret.data.source_type = this.isChinaDomain(item.url) ? ['all', 'cn'] : ['all', 'ov']
- return ret
- })
- this.initList()
- this.list.loading = false
- }).catch(err => {
- this.list.loading = false
- throw err
- })
- },
- isChinaDomain (url) {
- try {
- const { hostname } = new URL(url)
- return (
- hostname.endsWith('.cn') ||
- hostname.endsWith('.com.cn') ||
- hostname.endsWith('.net.cn') ||
- hostname.endsWith('.gov.cn') ||
- hostname.endsWith('.edu.cn') ||
- hostname.endsWith('.org.cn') ||
- hostname.includes('opencloudos')
- )
- } catch (e) {
- return false
- }
- },
- initList () {
- this.list.data = this.imageList.filter(item => {
- const { os_arch, distribution, source_type } = item.data
- if (this.form.os_arch && this.form.os_arch !== 'all' && os_arch !== this.form.os_arch) {
- return false
- }
- if (this.form.distribution && this.form.distribution !== 'all' && distribution !== this.form.distribution) {
- return false
- }
- if (this.form.source && !source_type.includes(this.form.source)) {
- return false
- }
- return true
- })
- },
- async handleConfirm () {
- this.loading = true
- try {
- for (let i = 0; i < this.selectedImages.length; i++) {
- const data = this.selectedImages[i]
- await new this.$Manager('images', 'v2').create({
- data: {
- domain_id: this.userInfo.projectDomainId,
- project_id: this.userInfo.projectId,
- copy_from: data.url,
- name: data.name,
- os_arch: data.os_arch,
- properties: {
- os_type: data.os_name,
- os_version: data.os_version,
- os_arch: data.os_arch,
- },
- },
- })
- }
- this.loading = false
- this.$router.push({ name: 'Image' })
- } catch (err) {
- this.$message.error(this.$t('common.failed'))
- this.loading = false
- throw err
- }
- },
- },
- }
- </script>
|