<template>
  <el-dialog
      title="Markdown 文件与TTS编辑"
      v-model="dialogVisible"
      width="85%"
      align-center
      :before-close="handleDialogClose"
  >
    <div class="input-section">
      <div class="form-group">
        <el-row>
          <el-col :span="24" style="border: 1px solid lightgray; padding: 10px;">
            <div style="display: flex; align-items: center; justify-content: space-between; margin-bottom: 10px;">
              <span style="font-weight: bold;">展品ID: {{formData.id}} - {{formData.label}}</span>
              <div style="display: flex; gap: 10px; align-items: center;">
                <span>Markdown文件地址:</span>
                <a v-if="formData.md_file_url" :href="formData.md_file_url" target="_blank" style="max-width: 300px; overflow: hidden; text-overflow: ellipsis;">
                  {{formData.md_file_url}}
                </a>
                <span v-else style="color: #999;">未上传</span>
              </div>
            </div>

            <!-- Markdown 文件上传区域 -->
            <div style="display: flex; align-items: center; gap: 10px; margin-bottom: 20px; padding: 10px; background: #f5f7fa; border-radius: 4px;">
              <el-upload
                  ref="uploadMdRef"
                  action=""
                  :auto-upload="false"
                  :limit="1"
                  :on-change="handleMdFileChange"
                  :on-exceed="handleMdFileExceed"
                  :show-file-list="false"
                  accept=".md,.markdown,.txt">
                <template #trigger>
                  <el-button type="primary" size="small">选择Markdown文件</el-button>
                </template>
              </el-upload>
              <span v-if="mdFile" style="color: #67C23A;">{{mdFile.name}}</span>
              <el-button
                  size="small"
                  type="success"
                  :disabled="!mdFile"
                  @click="submitMdFileUpload">
                上传并更新
              </el-button>
              <el-button
                  size="small"
                  type="danger"
                  :disabled="!formData.md_file_url"
                  @click="removeMdFileUrl">
                删除Markdown地址
              </el-button>
              <el-button
                  size="small"
                  type="info"
                  :disabled="!formData.md_file_url"
                  @click="loadMdContent">
                读取Markdown内容
              </el-button>
              <el-button
                  size="small"
                  type="warning"
                  :disabled="!formData.md_file_url || !mdContent || mdContent.length === 0"
                  @click="saveMdContent">
                保存修改到MinIO
              </el-button>
            </div>

            <!-- Markdown 内容编辑区域 -->
            <div style="margin-bottom: 20px;">
              <div style="display: flex; align-items: center; justify-content: space-between; margin-bottom: 10px;">
                <span style="font-weight: bold;">Markdown 内容编辑:</span>
                <span style="color: #909399; font-size: 12px;">字符数: {{mdContent.length}}</span>
              </div>
              <textarea
                  v-model="mdContent"
                  rows="15"
                  placeholder="请先上传Markdown文件或读取现有内容..."
                  style="width: 100%; font-family: monospace; padding: 10px; border: 1px solid #dcdfe6; border-radius: 4px;">
              </textarea>
            </div>
          </el-col>
        </el-row>
      </div>

      <!-- TTS 音频生成与上传区域 -->
      <div style="display: flex; align-items: center; justify-content: space-between; color: blue; margin: 10px 0;">
        <div>Markdown TTS 音频</div>
      </div>

      <el-row v-loading="isTTSGenerating" element-loading-text="音频生成中...">
        <el-col :span="24" style="border: 1px solid gray; padding: 15px;">
          <div style="display: flex; flex-direction: row; align-items: center; justify-content: flex-start; margin-bottom: 15px;">
            <span style="margin-right: 20px; display: inline-block; width: 200px;">TTS音频地址:</span>
            <span style="display: inline-block; flex: 1;">
              <a v-if="formData.md_tts_url" :href="formData.md_tts_url" target="_blank">{{formData.md_tts_url}}</a>
              <span v-else style="color: #999;">未生成</span>
            </span>
            <el-button
                type="danger"
                size="default"
                :disabled="!formData.md_tts_url"
                @click="removeMdTtsUrl">
              删除音频地址
            </el-button>
          </div>

          <div style="display: flex; align-items: center; justify-content: space-between; margin-bottom: 15px;">
            <div style="display: flex; justify-content: flex-start; align-items: center;">
              <label>音色选择：</label>
              <el-select
                  v-model="voiceSelected_md"
                  clearable
                  placeholder="请选择音色"
                  @change="voiceSelectedChangeMd"
                  allow-create
                  default-first-option
                  style="width: 140px;">
                <el-option
                    v-for="item in voiceOptions"
                    :key="item.value"
                    :label="item.label"
                    :value="item.value">
                </el-option>
              </el-select>
            </div>

            <el-button
                type="primary"
                :disabled="!mdContent || mdContent.length === 0"
                @click="generateMdTTS">
              生成语音
            </el-button>
            <audio class="audio-player" ref="audioPlayerMd" :src="preview.audioSrc_md" controls></audio>
            <el-button
                type="primary"
                :disabled="!preview.downReady_md"
                @click="downloadMdTTS">
              下载语音
            </el-button>
          </div>

          <div style="display: flex; align-items: center; justify-content: space-between; margin-bottom: 15px;">
            <div style="width: 90%; display: flex; justify-content: flex-start; align-items: center;">
              <span>下载文件名</span>
              <el-input v-model="downloadFilename_md"/>
            </div>
            <div style="display: flex; justify-content: flex-start; align-items: center;">
              <span style="display: inline-block; width: 100px;">{{downloadPromptMd}}</span>
            </div>
          </div>

          <!-- 上传区域 -->
          <div class="upload-section">
            <el-row v-show="preview.visible_md" align="middle" style="height: 5vh">
              <el-col :span="14">
                <div style="margin-left: 10px; width: 100%; height: 5vh; display: flex; align-items: center;">
                  <el-upload
                      action=""
                      :auto-upload="false"
                      :on-change="handleUploadChangeMd"
                      :show-file-list="false"
                      style="display: flex; align-items: center">
                    <template #trigger>
                      <el-button type="primary">选取文件</el-button>
                    </template>
                    <div style="display: inline-block; width: 200px;">{{uploadFileName_md}}</div>
                  </el-upload>
                </div>
              </el-col>
              <el-col :span="8">
                <el-button
                    :disabled="!uploadFile_md"
                    style="width: 90%;"
                    size="default"
                    type="success"
                    @click="submitMdTTSUpload">
                  上传并修改音频地址
                </el-button>
              </el-col>
            </el-row>
          </div>
        </el-col>
      </el-row>
    </div>

    <!-- 结果展示 -->
    <div class="result-section">
      <div v-if="result.error" class="error-message">
        错误：{{ result.error }}
      </div>
      <div v-if="result.success" class="success-message">
        <p>操作成功！</p>
      </div>
    </div>
  </el-dialog>
</template>

<script>
import {
  BASE_API_URL,
  WEIXIN_WS_URL,
  chatId,
  exhibit_tts_bucket_name,
  exhibit_md_bucket_name,
  exhibit_photo_bucket_name
} from "@/API/api";

export default {
  name: "MarkdownEditor",
  props: {
    'mesumSelectedId': {default: -1},
    'mesumSelected': {},
    'initData': {},
    'visible': {default: false},
    'photo_prefix': {default: 'temp'}
  },
  inject: {
    'root': {default: null},
    'getProject': {default: null},
    'getSchedule': {default: null}
  },
  data() {
    return {
      formData: {
        mesum_id: 1,
        id: "",
        label: "",
        md_file_url: "",
        md_tts_url: ""
      },
      mdFile: null,
      mdContent: "",
      preview: {
        visible_md: false,
        downReady_md: false,
        audioSrc_md: '',
        tempBlob_md: null
      },
      uploadFile_md: null,
      result: {
        error: null,
        success: false,
        minioUrl: ''
      },
      isTTSGenerating: false,
      voiceSelected_md: "sambert-zhichu-v1@Tongyi-Qianwen",
      downloadFilename_md: "md_tts.mp3",
      voiceOptions: [
        {"value": "cosyvoice-v1/longyuan@Tongyi-Qianwen", "label": "亲切女生"},
        {"value": "sambert-zhiru-v1@Tongyi-Qianwen", "label": "新闻女生"},
        {"value": "cosyvoice-v1/longhua@Tongyi-Qianwen", "label": "活泼女童"},
        {"value": "cosyvoice-v1/longxiang@Tongyi-Qianwen", "label": "解说男声"},
        {"value": "cosyvoice-v1/longyue@Tongyi-Qianwen", "label": "longyue"},
        {"value": "cosyvoice-v1/longwan@Tongyi-Qianwen", "label": "longwan"},
        {"value": "sambert-zhichu-v1@Tongyi-Qianwen", "label": "舌尖男声"},
        {"value": "sambert-zhiying-v1@Tongyi-Qianwen", "label": "软萌童声"},
      ],
      dialogVisible: false,
      downloadStateMd: 'idle',
    };
  },
  created() {
  },
  mounted() {
  },
  methods: {
    // Markdown 文件选择
    handleMdFileChange(file) {
      this.mdFile = file.raw;
      console.log("选择的Markdown文件:", file.name);
    },

    handleMdFileExceed(files) {
      this.$refs.uploadMdRef.clearFiles();
      const newFile = files[0];
      this.$refs.uploadMdRef.handleStart(newFile);
      this.handleMdFileChange({raw: newFile, name: newFile.name});
    },

    // 上传 Markdown 文件到 MinIO
    async submitMdFileUpload() {
      if (!this.mdFile) {
        this.$message.warning('请先选择Markdown文件');
        return;
      }

      try {
        // 如果已有MD文件，先删除旧的MinIO对象
        await this.removeMdFileFromMinio(this.formData.md_file_url);

        // 上传新文件
        const formData = new FormData();
        formData.append('file', this.mdFile);
        // 使用原始文件名，不重命名
        const fileName = this.mdFile.name;
        formData.append('bucket', exhibit_md_bucket_name); // 使用专门的bucket存放markdown
        formData.append('file_name', `${this.photo_prefix}/category/${fileName}`);

        const response = await fetch(`${BASE_API_URL}/minio/put`, {
          method: 'POST',
          body: formData,
          headers: {
            "Authorization": "Bearer ragflow-NhZTY5Y2M4YWQ1MzExZWY4Zjc3MDI0Mm"
          }
        });

        if (!response.ok) {
          throw new Error('上传失败');
        }

        const res = await response.json();
        const {data} = res;
        if (data?.put) {
          // 更新数据库
          await this.updateAntiqueMdFile(data?.url);
          this.$message.success('Markdown文件上传成功');
          this.mdFile = null;
          if (this.$refs.uploadMdRef) {
            this.$refs.uploadMdRef.clearFiles();
          }
        }
      } catch (error) {
        console.error('上传Markdown文件失败:', error);
        this.$message.error('上传Markdown文件失败');
      }
    },

    // 读取 Markdown 文件内容
    async loadMdContent() {
      if (!this.formData.md_file_url) {
        this.$message.warning('没有Markdown文件URL');
        return;
      }

      try {
        // 添加时间戳参数避免浏览器缓存
        const url = this.formData.md_file_url + '?t=' + Date.now();
        const response = await fetch(url);
        if (!response.ok) {
          throw new Error('读取文件失败');
        }
        const content = await response.text();
        this.mdContent = content;
        this.$message.success('Markdown内容加载成功');
      } catch (error) {
        console.error('读取Markdown内容失败:', error);
        this.$message.error('读取Markdown内容失败');
      }
    },

    // 保存 Markdown 内容修改到 MinIO
    async saveMdContent() {
      if (!this.formData.md_file_url) {
        this.$message.warning('没有Markdown文件URL');
        return;
      }

      if (!this.mdContent || this.mdContent.length === 0) {
        this.$message.warning('Markdown内容为空');
        return;
      }

      try {
        const loading = this.$loading({
          lock: true,
          text: '正在保存Markdown内容到MinIO...',
          background: 'rgba(0, 0, 0, 0.7)'
        });

        // 从URL中解析出bucket和文件名
        let bucket = exhibit_md_bucket_name;
        let fileName = '';
        
        const urlParts = this.formData.md_file_url.split(`${exhibit_md_bucket_name}/`);
        if (urlParts.length > 1) {
          fileName = urlParts[1];
        } else {
          // 兼容旧的photo bucket格式
          const photoUrlParts = this.formData.md_file_url.split(`${exhibit_photo_bucket_name}/`);
          if (photoUrlParts.length > 1) {
            bucket = exhibit_photo_bucket_name;
            fileName = photoUrlParts[1];
          } else {
            throw new Error('无法解析文件路径');
          }
        }

        // 将Markdown内容转换为Blob
        const blob = new Blob([this.mdContent], { type: 'text/markdown' });
        const file = new File([blob], fileName.split('/').pop() || 'content.md', { type: 'text/markdown' });

        // 先删除旧文件（根据经验记忆，某些MinIO版本需要先删除再上传）
        await this.removeMinioObject(bucket, fileName);

        // 上传新内容
        const formData = new FormData();
        formData.append('file', file);
        formData.append('bucket', bucket);
        formData.append('file_name', fileName);

        const response = await fetch(`${BASE_API_URL}/minio/put`, {
          method: 'POST',
          body: formData,
          headers: {
            "Authorization": "Bearer ragflow-NhZTY5Y2M4YWQ1MzExZWY4Zjc3MDI0Mm"
          }
        });

        if (!response.ok) {
          throw new Error('上传失败');
        }

        const res = await response.json();
        const {data} = res;
        
        if (data?.put) {
          // 验证上传是否成功：下载文件并检查内容
          const verifyResponse = await fetch(this.formData.md_file_url + '?t=' + Date.now());
          if (verifyResponse.ok) {
            const verifyContent = await verifyResponse.text();
            if (verifyContent === this.mdContent) {
              loading.close();
              this.$message.success('Markdown内容已成功保存到MinIO并验证通过');
            } else {
              loading.close();
              this.$message.warning('Markdown内容已上传，但验证发现内容可能未完全更新，请刷新后重试');
            }
          } else {
            loading.close();
            this.$message.success('Markdown内容已保存到MinIO');
          }
        } else {
          loading.close();
          this.$message.error('保存失败：服务器返回失败状态');
        }
      } catch (error) {
        console.error('保存Markdown内容到MinIO失败:', error);
        this.$message.error('保存Markdown内容失败: ' + error.message);
      }
    },

    // 从MD文件URL中删除MinIO对象（独立函数）
    async removeMdFileFromMinio(md_file_url) {
      if (!md_file_url || md_file_url === '') {
        return;
      }

      const urlParts = md_file_url.split(`${exhibit_md_bucket_name}/`);
      if (urlParts.length > 1) {
        const fileName = urlParts[1];
        if (fileName && fileName !== "") {
          await this.removeMinioObject(exhibit_md_bucket_name, fileName);
          console.log('已删除Markdown文件:', fileName);
        }
      } else {
        // 兼容旧的URL格式或其他bucket
        const photoUrlParts = md_file_url.split(`${exhibit_photo_bucket_name}/`);
        if (photoUrlParts.length > 1) {
          const fileName = photoUrlParts[1];
          if (fileName && fileName !== "") {
            await this.removeMinioObject(exhibit_photo_bucket_name, fileName);
            console.log('已删除Markdown文件(photo bucket):', fileName);
          }
        }
      }
    },

    // 删除 Markdown 文件URL
    async removeMdFileUrl() {
      this.$confirm('确认删除Markdown文件地址？')
          .then(async () => {
            // 调用独立的删除函数
            await this.removeMdFileFromMinio(this.formData.md_file_url);

            await this.updateAntiqueMdFile("");
            this.mdContent = "";
            this.$message.success('删除Markdown文件地址成功');
          }).catch(() => {});
    },

    // 更新数据库中的 md_file_url
    async updateAntiqueMdFile(md_file_url) {
      let antique_data = {
        mesum_id: this.mesumSelectedId,
        md_file_url: md_file_url
      };

      const response = await fetch(`${BASE_API_URL}/mesum/antique/update/${this.formData.mesum_id}/${this.formData.id}`, {
        method: 'POST',
        headers: {
          'Content-Type': 'application/json',
          'Authorization': 'Bearer ragflow-NhZTY5Y2M4YWQ1MzExZWY4Zjc3MDI0Mm'
        },
        body: JSON.stringify(antique_data)
      });

      const result = await response.json();
      const {data} = result;
      if (data && data.update) {
        this.formData.md_file_url = md_file_url;
        this.triggerRefreshAntiques();
        return true;
      }
      return false;
    },

    // 生成 Markdown TTS
    async generateMdTTS() {
      if (!this.mdContent || this.mdContent.length === 0) {
        this.$message.warning('Markdown内容为空，无法生成语音');
        return;
      }

      this.downloadFilename_md = 'md_tts_' + window.pinyin.getFullChars(this.formData.label) + '.mp3';

      try {
        this.isTTSGenerating = true;
        this.preview.audioSrc_md = null;
        this.preview.downReady_md = false;

        const wsUrl = `${WEIXIN_WS_URL}/tts/chats/${chatId}/tts/x-tts-type-is-TextToTts`;
        const ws = new WebSocket(wsUrl);

        let audioChunks = [];

        ws.onopen = () => {
          ws.send(JSON.stringify({
            service_type: "TextToTts",
            text: this.mdContent,
            params: {
              tts_stream_format: 'mp3',
              tts_sample_rate: 22050,
              model_name: this.voiceSelected_md,
              delay_gen_audio: true
            }
          }));
        };

        ws.onmessage = async (event) => {
          if (typeof event.data === 'string') {
            try {
              const message = JSON.parse(event.data);
              if (message.error) {
                this.showError(message.error);
              } else if (message.status === "completed") {
                ws.close();
              }
            } catch (e) {
              console.log("Non-JSON message:", event.data);
            }
          } else {
            audioChunks.push(event.data);
            console.log("收到音频数据", event.data.size);
          }
        };

        ws.onclose = () => {
          this.isTTSGenerating = false;

          if (audioChunks.length > 0) {
            const blob = new Blob(audioChunks, {type: 'audio/mpeg'});
            const url = URL.createObjectURL(blob);

            if (this.preview.audioSrc_md) {
              URL.revokeObjectURL(this.preview.audioSrc_md);
            }
            this.preview.audioSrc_md = url;
            this.preview.tempBlob_md = blob;
            this.preview.downReady_md = true;
            this.preview.visible_md = false;
          }
        };

        ws.onerror = (error) => {
          this.isTTSGenerating = false;
          this.showError("WebSocket连接错误: " + error.message);
        };

      } catch (error) {
        this.isTTSGenerating = false;
        this.showError(error.message);
      }
    },

    // 下载 Markdown TTS
    downloadMdTTS() {
      this.downloadFile(this.preview.audioSrc_md, this.downloadFilename_md);
    },

    downloadFile(content, filename) {
      let blob = this.preview.tempBlob_md;
      this.downloadStateMd = "download";

      if (!blob) {
        this.showError("没有可下载的音频");
        return;
      }

      const url = URL.createObjectURL(blob);
      const a = document.createElement('a');
      a.href = url;
      a.download = filename;
      document.body.appendChild(a);
      a.click();

      URL.revokeObjectURL(url);
      document.body.removeChild(a);

      this.preview.visible_md = true;
      this.downloadStateMd = "finished";
      this.resetDownloadState();
    },

    // 音色选择变化
    // eslint-disable-next-line no-unused-vars
    voiceSelectedChangeMd(value) {
      this.preview.visible_md = false;
      this.preview.audioSrc_md = "";
    },

    // 处理上传文件变化
    handleUploadChangeMd(file) {
      console.log(file);
      this.uploadFile_md = file.raw;
    },

    // 提交 TTS 上传
    submitMdTTSUpload() {
      const formData = new FormData();
      formData.append('file', this.uploadFile_md);
      formData.append('bucket', exhibit_tts_bucket_name);
      formData.append('file_name', `${this.photo_prefix}/${this.uploadFileName_md}`);

      fetch(`${BASE_API_URL}/minio/put`, {
        method: 'POST',
        body: formData,
        headers: {
          "Authorization": "Bearer ragflow-NhZTY5Y2M4YWQ1MzExZWY4Zjc3MDI0Mm"
        }
      })
          .then(response => {
            if (!response.ok) {
              throw new Error('Network response was not ok');
            }
            return response.json();
          })
          .then(res => {
            const {data} = res;
            if (data?.put) {
              this.updateAntiqueMdTts(data?.url);
              this.$message.success('上传成功');
            }
          })
          .catch(error => {
            console.error('上传失败:', error);
            this.$message.error('上传失败');
          });
    },

    // 删除 Markdown TTS URL
    async removeMdTtsUrl() {
      this.$confirm('确认删除Markdown TTS音频地址？')
          .then(async () => {
            if (this.formData.md_tts_url && this.formData.md_tts_url !== '') {
              const urlParts = this.formData.md_tts_url.split(`${exhibit_tts_bucket_name}/`);
              if (urlParts.length > 1) {
                const fileName = urlParts[1];
                if (fileName && fileName !== "") {
                  await this.removeMinioObject(exhibit_tts_bucket_name, fileName);
                }
              }
            }

            if (await this.updateAntiqueMdTts("")) {
              this.$message('删除音频地址成功');
            } else {
              this.$message('删除音频地址失败');
            }
          }).catch(() => {
      });
    },

    // 更新数据库中的 md_tts_url
    async updateAntiqueMdTts(tts_url) {
      let antique_data = {
        mesum_id: this.mesumSelectedId,
        md_tts_url: tts_url
      };

      const response = await fetch(`${BASE_API_URL}/mesum/antique/update/${this.formData.mesum_id}/${this.formData.id}`, {
        method: 'POST',
        headers: {
          'Content-Type': 'application/json',
          'Authorization': 'Bearer ragflow-NhZTY5Y2M4YWQ1MzExZWY4Zjc3MDI0Mm'
        },
        body: JSON.stringify(antique_data)
      });

      const result = await response.json();
      const {data} = result;
      if (data && data.update) {
        this.formData.md_tts_url = tts_url;
        this.triggerRefreshAntiques();
        return true;
      }
      return false;
    },

    // 删除 MinIO 对象
    async removeMinioObject(bucket, fileName) {
      fetch(`${BASE_API_URL}/minio/rm`, {
        method: 'POST',
        body: JSON.stringify({
          bucket: bucket,
          file_name: fileName
        }),
        headers: {
          "Content-Type": "application/json",
          "Authorization": "Bearer ragflow-NhZTY5Y2M4YWQ1MzExZWY4Zjc3MDI0Mm"
        }
      })
          .then(response => {
            if (!response.ok) {
              throw new Error('Network response was not ok');
            }
            return response.json();
          })
          .then(res => {
            const {data} = res;
            if (data?.rm) {
              console.log('删除MinIO对象成功');
            }
          })
          .catch(error => {
            console.error('删除minio object 失败:', error);
          });
    },

    resetDownloadState() {
      setTimeout(() => {
        this.downloadStateMd = 'idle';
      }, 3000);
    },

    showError(message) {
      this.result.error = message;
      this.result.success = false;
      setTimeout(() => this.result.error = null, 5000);
    },

    handleDialogClose(done) {
      const audioMd = this.$refs.audioPlayerMd;
      if (audioMd) {
        audioMd.pause();
      }
      done();
      this.closeDialog();
    },

    closeDialog() {
      this.dialogVisible = false;
      this.$emit("update:close", true);
    },

    triggerRefreshAntiques() {
      this.$emit("update:refresh", this.formData.id);
    }
  },
  watch: {
    visible: {
      handler(newVal) {
        this.dialogVisible = newVal;
        if (newVal) {
          this.formData = {...this.formData, ...this.initData};
          this.mdContent = "";
          this.mdFile = null;
          this.downloadStateMd = 'idle';
          this.downloadFilename_md = 'md_tts_' + window.pinyin.getFullChars(this.formData.label || 'default') + '.mp3';
        }
        console.log("watch visible", newVal, this.initData);
      },
      immediate: true
    },
    mesumSelectedId: {
      handler(newVal) {
        console.log("watch mesumSelectedId", newVal);
        if (newVal == 2) {
          this.voiceSelected_md = "sambert-zhichu-v1@Tongyi-Qianwen";
        } else if (newVal == 1) {
          this.voiceSelected_md = "cosyvoice-v1/longyuan@Tongyi-Qianwen";
        } else {
          this.voiceSelected_md = "sambert-zhichu-v1@Tongyi-Qianwen";
        }
      },
      immediate: true
    }
  },
  computed: {
    uploadFileName_md() {
      if (this.uploadFile_md && this.uploadFile_md.name)
        return this.uploadFile_md.name;
      else
        return "";
    },
    downloadPromptMd() {
      if (this.downloadStateMd === 'idle') return "";
      if (this.downloadStateMd === 'download') return "下载中...";
      if (this.downloadStateMd === 'save') return "存储中...";
      if (this.downloadStateMd === 'finished') return "完成";
      return "";
    }
  }
}
</script>

<style scoped>
.dialog-footer {
  display: flex;
  justify-content: flex-end;
}

.el-dialog__header {
  background: #f0f9eb !important;
  padding: 2px 2px !important;
  border-bottom: 1px solid #ebeef5;
}

.el-dialog__title {
  margin: 0;
  padding: 0;
  color: #67C23A !important;
  font-size: 16px !important;
}

.el-dialog__headerbtn {
  margin-top: 3px !important;
  top: 2px !important;
}

.form-group {
  padding: 5px;
  margin-bottom: 5px;
  border-bottom: 2px solid #eee;
}

label {
  display: block;
  margin-bottom: 5px;
}

input, select, textarea {
  width: 100%;
  padding: 8px;
}

button {
  padding: 10px 20px;
  margin: 5px;
  cursor: pointer;
}

.audio-player {
  margin: 20px 0;
  height: 40px
}

.error-message {
  color: red;
  margin-top: 10px;
}

.success-message {
  color: green;
  margin-top: 10px;
}

.upload-section {
  margin-top: 20px;
  border-top: 2px solid #eee;
  padding-top: 20px;
  height: 10vh
}
</style>
