| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274 |
- <template>
- <div class="device-action-container">
- <div class="content-body">
- <div class="form-row">
- <label class="form-label">升级文件</label>
- <div class="upload-wrapper">
- <div class="mock-input" @click="triggerUpload" :class="{ 'is-disabled': isLoading }">
- <span class="file-name" v-if="fileName">{{ fileName }}</span>
- <span class="placeholder" v-else></span>
- <i class="el-icon-plus add-icon">+</i>
- </div>
- <input type="file" ref="fileInput" class="hidden-file-input" @change="handleFileChange"
- accept=".bin,.zip,.tar.gz" :disabled="isLoading" />
- <button class="btn-primary upload-btn" @click="triggerUpload" :disabled="isLoading">
- 上传
- </button>
- </div>
- </div>
- </div>
- <div class="dialog-footer">
- <div class="action-text">
- 操作:<span class="highlight">升级</span>
- </div>
- <div class="action-buttons">
- <button class="btn-default" @click="cancel" :disabled="isLoading">取消</button>
- <button class="btn-primary" @click="confirm" :disabled="isLoading">
- <i v-if="isLoading" class="loading-spinner"></i>
- {{ isLoading ? '上传中...' : '确认' }}
- </button>
- </div>
- </div>
- </div>
- </template>
- <script>
- export default {
- name: 'DeviceUpgrade',
- props: {
- nodeId: {
- type: [String, Number],
- default: ''
- },
- onClose: {
- type: Function,
- default: null
- }
- },
- data() {
- return {
- fileName: '',
- isLoading: false // 新增 loading 状态
- };
- },
- methods: {
- triggerUpload() {
- if (this.isLoading) return; // 上传中禁止重新选文件
- this.$refs.fileInput.click();
- },
- handleFileChange(event) {
- const file = event.target.files[0];
- if (file) {
- this.fileName = file.name;
- }
- },
- cancel() {
- if (this.onClose) this.onClose();
- },
- // 将 confirm 改为异步方法
- async confirm() {
- if (!this.fileName) {
- alert('请先选择升级文件'); // 建议替换为 Element UI 的 this.$message.warning
- return;
- }
- this.isLoading = true; // 开启 loading
- try {
- // 模拟 API 请求 (用 setTimeout 模拟网络延迟 2 秒)
- // 真实业务中请替换为:await this.$http.post('/api/upgrade', formData)
- await new Promise(resolve => setTimeout(resolve, 2000));
- console.log(`节点ID: ${this.nodeId}, 文件: ${this.fileName} 升级成功`);
- // 可选:提示成功 this.$message.success('升级任务下发成功');
- if (this.onClose) this.onClose(); // 请求成功后才关闭弹窗
- } catch (error) {
- console.error('升级失败', error);
- // 可选:提示失败 this.$message.error('升级失败,请重试');
- } finally {
- this.isLoading = false; // 无论成功失败,重置 loading 状态
- }
- }
- }
- };
- </script>
- <style scoped>
- /* 此处保留上一版的全部 CSS,只在最下面追加 Loading 和 Disabled 相关的样式 */
- * {
- box-sizing: border-box;
- }
- .device-action-container {
- display: flex;
- flex-direction: column;
- height: 100%;
- width: 100%;
- color: #c0c4cc;
- font-size: 14px;
- }
- .content-body {
- flex: 1;
- display: flex;
- align-items: center;
- padding: 0 20px;
- }
- .form-row {
- display: flex;
- align-items: center;
- width: 100%;
- }
- .form-label {
- width: 70px;
- text-align: right;
- margin-right: 15px;
- white-space: nowrap;
- flex-shrink: 0;
- }
- .upload-wrapper {
- display: flex;
- flex: 1;
- align-items: center;
- gap: 10px;
- min-width: 0;
- }
- .mock-input {
- flex: 1;
- min-width: 0;
- height: 32px;
- background: rgba(16, 36, 70, 0.5);
- border: 1px solid #2a4c85;
- border-radius: 4px;
- display: flex;
- justify-content: space-between;
- align-items: center;
- padding: 0 10px;
- cursor: pointer;
- transition: border-color 0.2s;
- }
- .mock-input:hover:not(.is-disabled) {
- border-color: #3e73ff;
- }
- .file-name {
- color: #fff;
- flex: 1;
- margin-right: 10px;
- overflow: hidden;
- text-overflow: ellipsis;
- white-space: nowrap;
- }
- .add-icon {
- color: #8fb3ff;
- font-size: 16px;
- font-weight: bold;
- flex-shrink: 0;
- }
- .hidden-file-input {
- display: none;
- }
- .upload-btn {
- flex-shrink: 0;
- white-space: nowrap;
- }
- .dialog-footer {
- border-top: 1px solid rgba(42, 76, 133, 0.5);
- padding: 12px 20px;
- display: flex;
- justify-content: space-between;
- align-items: center;
- flex-shrink: 0;
- }
- .action-text {
- color: #c0c4cc;
- white-space: nowrap;
- }
- .action-text .highlight {
- color: #1e6fff;
- }
- .action-buttons {
- display: flex;
- gap: 15px;
- flex-shrink: 0;
- }
- button {
- height: 32px;
- padding: 0 20px;
- border-radius: 4px;
- cursor: pointer;
- font-size: 14px;
- outline: none;
- transition: all 0.2s;
- display: inline-flex;
- align-items: center;
- justify-content: center;
- }
- .btn-primary {
- background: #1e6fff;
- border: 1px solid #1e6fff;
- color: #fff;
- }
- .btn-primary:hover:not(:disabled) {
- background: #3e83ff;
- border-color: #3e83ff;
- }
- .btn-default {
- background: transparent;
- border: 1px solid #2a4c85;
- color: #c0c4cc;
- }
- .btn-default:hover:not(:disabled) {
- border-color: #3e73ff;
- color: #fff;
- }
- /* ================= 新增:Disabled 与 Loading 样式 ================= */
- .is-disabled {
- cursor: not-allowed;
- opacity: 0.6;
- }
- button:disabled {
- cursor: not-allowed;
- opacity: 0.6;
- /* 防止被禁用时发生位移或颜色突变 */
- }
- /* 简单的 CSS 旋转动画 */
- .loading-spinner {
- display: inline-block;
- width: 14px;
- height: 14px;
- border: 2px solid rgba(255, 255, 255, 0.3);
- border-radius: 50%;
- border-top-color: #ffffff;
- animation: spin 1s linear infinite;
- margin-right: 6px;
- }
- @keyframes spin {
- to {
- transform: rotate(360deg);
- }
- }
- </style>
|