| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297 |
- <template>
- <div class="ml20 mt20 mr20 flex-row flex-align-center flex-justify-between">
- <div class="flex-row">
- <a-button type="primary" @click="sVisible = true">
- Click to Upload
- </a-button>
- <a-modal :visible="sVisible" title="Import Firmware File" :closable="false" @cancel="onCancel" @ok="uploadFile"
- centered>
- <a-form :rules="rules" ref="formRef" :model="uploadParam" :label-col="{ span: 6 }">
- <a-form-item name="status" label="Avaliable" required>
- <a-switch v-model:checked="uploadParam.status" />
- </a-form-item>
- <a-form-item name="device_name" label="Device Name" required>
- <a-select style="width: 220px" mode="multiple" placeholder="can choose multiple"
- v-model:value="uploadParam.device_name">
- <a-select-option v-for="k in DeviceNameEnum" :key="k" :value="k">
- {{ k }}
- </a-select-option>
- </a-select>
- </a-form-item>
- <a-form-item name="release_note" label="Release Note" required>
- <a-textarea v-model:value="uploadParam.release_note" showCount :maxlength="300" />
- </a-form-item>
- <a-form-item label="File" required>
- <a-upload :multiple="false" :before-upload="beforeUpload" :show-upload-list="true" :file-list="fileList"
- :remove="removeFile">
- <a-button type="primary">
- <UploadOutlined />
- Import Firmware File
- </a-button>
- </a-upload>
- </a-form-item>
- </a-form>
- </a-modal>
- </div>
- <div class="flex-row">
- <div class="ml5">
- <a-select style="width: 150px" v-model:value="param.firmware_status" @select="getAllFirmwares(pageParam)">
- <a-select-option v-for="(key, value) in FirmwareStatusEnum" :key="key" :value="value">
- {{ key }}
- </a-select-option>
- </a-select>
- </div>
- <div class="ml5">
- <a-select style="width: 150px" v-model:value="param.device_name" @select="getAllFirmwares(pageParam)">
- <a-select-option v-for="item in deviceNameList" :key="item.label" :value="item.value">
- {{ item.label }}
- </a-select-option>
- </a-select>
- </div>
- <div class="ml5">
- <a-input-search :enter-button="true" v-model:value="param.product_version" placeholder="input search verison"
- style="width: 250px" @search="getAllFirmwares(pageParam)" />
- </div>
- </div>
- </div>
- <div class="table flex-display flex-column">
- <a-table :columns="columns" :data-source="data.firmware" :pagination="paginationProp" @change="refreshData"
- row-key="firmware_id" :rowClassName="(record, index) => ((index % 2) === 0 ? 'table-striped' : null)"
- :scroll="{ x: '100%', y: 600 }">
- <template #device_name="{ record }">
- <div v-for="text in record.device_name" :key="text">
- {{ text }}
- </div>
- </template>
- <template #file_size="{ record }">
- <div>{{ bytesToSize(record.file_size) }}</div>
- </template>
- <template #firmware_status="{ record }">
- <DeviceFirmwareStatus :firmware="record" />
- </template>
- <template v-for="col in ['file_name', 'release_note']" #[col]="{ text }" :key="col">
- <a-tooltip :title="text">
- <span>{{ text }}</span>
- </a-tooltip>
- </template>
- </a-table>
- </div>
- </template>
- <script lang="ts" setup>
- import { onMounted, reactive, ref } from 'vue'
- import { message, notification } from 'ant-design-vue'
- import { UploadOutlined } from '@ant-design/icons-vue'
- import { TableState } from 'ant-design-vue/lib/table/interface'
- import { IPage } from '/@/api/http/type'
- import { getFirmwares, importFirmareFile } from '/@/api/manage'
- import DeviceFirmwareStatus from '/@/components/devices/DeviceFirmwareStatus.vue'
- import { Firmware, FirmwareQueryParam, FirmwareStatusEnum, DeviceNameEnum, FirmwareUploadParam } from '/@/types/device-firmware'
- import { commonColor } from '/@/utils/color'
- import { bytesToSize } from '/@/utils/bytes'
- import { getWorkspaceId } from '/@/utils'
- import moment from 'moment'
- interface FirmwareData {
- firmware: Firmware[]
- }
- const columns = [
- { title: 'Model', dataIndex: 'device_name', width: 120, ellipsis: true, className: 'titleStyle', slots: { customRender: 'device_name' } },
- { title: 'File Name', dataIndex: 'file_name', width: 220, ellipsis: true, className: 'titleStyle', slots: { customRender: 'file_name' } },
- { title: 'Firmware Version', dataIndex: 'product_version', width: 180, className: 'titleStyle' },
- { title: 'File Size', dataIndex: 'file_size', width: 150, className: 'titleStyle', slots: { customRender: 'file_size' } },
- { title: 'Creator', dataIndex: 'username', width: 100, className: 'titleStyle' },
- { title: 'Release Date', dataIndex: 'released_time', width: 160, sorter: (a: Firmware, b: Firmware) => a.released_time.localeCompare(b.released_time), className: 'titleStyle' },
- { title: 'Release Note', dataIndex: 'release_note', width: 300, ellipsis: true, className: 'titleStyle', slots: { customRender: 'release_note' } },
- { title: 'Status', dataIndex: 'firmware_status', width: 100, className: 'titleStyle', slots: { customRender: 'firmware_status' } },
- ]
- const data = reactive<FirmwareData>({
- firmware: []
- })
- const paginationProp = reactive({
- pageSizeOptions: ['20', '50', '100'],
- showQuickJumper: true,
- showSizeChanger: true,
- pageSize: 50,
- current: 1,
- total: 0
- })
- const deviceNameList = ref<any[]>([{ label: 'All', value: '' }])
- type Pagination = TableState['pagination']
- const pageParam: IPage = {
- page: 1,
- total: 0,
- page_size: 50
- }
- const param = reactive<FirmwareQueryParam>({
- product_version: '',
- device_name: '',
- firmware_status: FirmwareStatusEnum.NONE
- })
- onMounted(() => {
- getAllFirmwares(pageParam)
- for (const key in DeviceNameEnum) {
- const value = DeviceNameEnum[key]
- deviceNameList.value.push({ label: value, value: value })
- }
- })
- function refreshData(page: Pagination) {
- pageParam.page = page?.current!
- pageParam.page_size = page?.pageSize!
- getAllFirmwares(pageParam)
- }
- function getAllFirmwares(page: IPage) {
- getFirmwares(getWorkspaceId(), page, param).then(res => {
- const firmwareList: Firmware[] = res.data.list
- data.firmware = firmwareList
- paginationProp.total = res.data.pagination.total
- paginationProp.current = res.data.pagination.page
- })
- }
- const sVisible = ref(false)
- const uploadParam = reactive<FirmwareUploadParam>({
- device_name: [],
- release_note: '',
- status: true
- })
- const rules = {
- status: [{ required: true }],
- release_note: [{ required: true, message: 'Please input release note.' }],
- device_name: [{ required: true, message: 'Please select which models this firmware belongs to.' }]
- }
- interface FileItem {
- uid: string;
- name?: string;
- status?: string;
- response?: string;
- url?: string;
- }
- interface FileInfo {
- file: FileItem;
- fileList: FileItem[];
- }
- const fileList = ref<FileItem[]>([])
- function beforeUpload(file: FileItem) {
- if (!file.name || !file.name?.endsWith('.zip')) {
- message.error('Format error. Please select zip file.')
- return false
- }
- fileList.value = [file]
- return false
- }
- const formRef = ref()
- function removeFile(file: FileItem) {
- fileList.value = []
- }
- function onCancel() {
- formRef.value.resetFields()
- fileList.value = []
- sVisible.value = false
- }
- const uploadFile = async () => {
- if (fileList.value.length === 0) {
- message.error('Please select at least one file.')
- }
- let uploading: string
- formRef.value.validate().then(async () => {
- const file: FileItem = fileList.value[0]
- const fileData = new FormData()
- fileData.append('file', file as any, file.name)
- Object.keys(uploadParam).forEach((key) => {
- const val = uploadParam[key as keyof FirmwareUploadParam]
- if (val instanceof Array) {
- val.forEach((value) => {
- fileData.append(key, value)
- })
- } else {
- fileData.append(key, val.toString())
- }
- })
- const timestamp = new Date().getTime()
- uploading = (file.name ?? 'uploding') + timestamp
- notification.open({
- key: uploading,
- message: `Uploading ${moment().format()}`,
- description: `[${file.name}] is uploading... `,
- duration: null
- })
- importFirmareFile(getWorkspaceId(), fileData).then((res) => {
- if (res.code === 0) {
- notification.success({
- message: `Uploaded ${moment().format()}`,
- description: `[${file.name}] file uploaded successfully. Duration: ${moment.duration(new Date().getTime() - timestamp).asSeconds()}`,
- duration: null
- })
- getAllFirmwares(pageParam)
- } else {
- notification.error({
- message: `Failed to upload [${file.name}]. Check and try again.`,
- description: `Error message: ${res.message} ${moment().format()}`,
- style: { color: commonColor.FAIL },
- duration: null,
- })
- }
- }).finally(() => {
- notification.close(uploading)
- })
- fileList.value = []
- formRef.value.resetFields()
- sVisible.value = false
- })
- }
- </script>
- <style>
- .table {
- background-color: white;
- margin: 20px;
- padding: 20px;
- height: 88vh;
- }
- .table-striped {
- background-color: #f7f9fa;
- }
- .ant-table {
- border-top: 1px solid rgb(0, 0, 0, 0.06);
- border-bottom: 1px solid rgb(0, 0, 0, 0.06);
- }
- .ant-table-tbody tr td {
- border: 0;
- }
- .ant-table td {
- white-space: nowrap;
- }
- .ant-table-thead tr th {
- background: white !important;
- border: 0;
- }
- th.ant-table-selection-column {
- background-color: white !important;
- }
- .ant-table-header {
- background-color: white !important;
- }
- </style>
|