<template>
  <div class="order-detail" v-loading="loading">
    <el-page-header :icon="ArrowLeft" :content="$t('common.back')" @back="goBack" class="page-header">
      <template #content>
        <span class="page-title">{{ $t('modal.detail') }}</span>
      </template>
    </el-page-header>

    <el-card shadow="never" v-if="detail.id" class="detail-card">
      <template #header>
        <div class="card-header">
          <span class="title">{{ detail.title }}</span>
          <el-tag :type="priorityType(detail.priority)" size="small">{{ detail.priority }}</el-tag>
          <el-tag :type="statusType(detail.status)" size="small">{{ detail.status }}</el-tag>
          <el-button
            v-if="detail.status !== '已完成'"
            type="primary"
            size="small"
            style="margin-left:auto"
            @click="openEdit"
          >
            {{ $t('btn.edit') }}
          </el-button>
        </div>
      </template>

      <el-descriptions :column="3" border>
        <el-descriptions-item :label="$t('table.id')">{{ detail.orderNo }}</el-descriptions-item>
        <el-descriptions-item :label="$t('table.hospital')">{{ detail.hospitalName }}</el-descriptions-item>
        <el-descriptions-item :label="$t('table.type')">{{ detail.serviceType }}</el-descriptions-item>
        <el-descriptions-item :label="$t('table.submitter')">{{ detail.submitter }}</el-descriptions-item>
        <el-descriptions-item :label="$t('label.dept')">{{ detail.department }}</el-descriptions-item>
        <el-descriptions-item :label="$t('table.time')">{{ detail.createdAt?.split('T').join(' ') }}</el-descriptions-item>
      </el-descriptions>

      <div class="section">
        <div class="section-title">{{ $t('label.description') }}</div>
        <div class="html-content" v-html="detail.description || '—'" />
      </div>

      <div class="section">
        <div class="section-title">{{ $t('label.attachment') }}</div>
        <el-empty v-if="!detail.attachments?.length" :description="$t('orderDetail.noAttachment')" :image-size="80" />
        <div v-else class="files">
          <el-button
            v-for="(f, i) in detail.attachments"
            :key="i"
            link
            type="primary"
            class="file-item"
            @click="viewReport(f.filePath, f.fileName)"
          >
            <el-icon><Document /></el-icon>{{ f.fileName }}
          </el-button>
        </div>
      </div>

      <div class="section">
        <div class="section-title">{{ $t('orderDetail.statusChange') }}</div>
        <el-timeline>
          <el-timeline-item
            v-for="(log, i) in detail.statusLogs || []"
            :key="i"
            :timestamp="log.createdAt"
            placement="top"
          >
            <div class="log-title">{{ log.toStatus }} · {{ log.operator }}</div>
            <div class="log-remark" v-html="log.remark"></div>
          </el-timeline-item>
        </el-timeline>
      </div>
    </el-card>

    <!-- 编辑工单弹窗 -->
    <el-dialog
      v-model="editVisible"
      :title="$t('modal.edit')"
      width="640px"
      :close-on-click-modal="false"
      @closed="onEditClosed"
    >
      <el-form
        ref="editFormRef"
        :model="editForm"
        :rules="editRules"
        label-width="100px"
        v-loading="editLoading"
      >
        <el-form-item :label="$t('label.hospitalName')" prop="hospitalId">
          <el-select
            v-model="editForm.hospitalId"
            :placeholder="$t('msg.pleaseSelectHospital')"
            filterable
            style="width: 100%"
          >
            <el-option
              v-for="h in hospitals"
              :key="h.id"
              :label="h.name"
              :value="h.id"
            />
          </el-select>
        </el-form-item>
        <el-form-item :label="$t('label.title')" prop="title">
          <div class="title-row">
            <el-input
              v-model="editForm.title"
              :placeholder="$t('placeholder.title')"
              maxlength="100"
              show-word-limit
            />
            <div class="color-tag-picker" ref="editColorPickerRef">
              <div
                class="color-tag-preview"
                :style="{ background: editForm.colorTag || '#dcdfe6' }"
                :class="{ 'is-empty': !editForm.colorTag }"
                @click.stop="toggleEditColorPicker"
              ></div>
              <div
                v-show="editColorPickerVisible"
                class="color-tag-dropdown"
                @click.stop
              >
                <div class="color-tag-title">{{ $t("label.colorTag") }}</div>
                <div class="color-tag-options">
                  <div
                    v-for="c in colorOptions"
                    :key="c.value"
                    class="color-tag-option"
                    :class="{ active: editForm.colorTag === c.value }"
                    :style="{ background: c.value }"
                    :title="c.label"
                    @click="selectEditColor(c.value)"
                  ></div>
                </div>
              </div>
            </div>
          </div>
        </el-form-item>
        <el-form-item :label="$t('label.type')" prop="serviceType">
          <el-select
            v-model="editForm.serviceType"
            :placeholder="$t('placeholder.type')"
            clearable
          >
            <el-option label="故障问题" value="故障问题" />
            <el-option label="使用咨询" value="使用咨询" />
            <el-option label="功能需求" value="功能需求" />
            <el-option label="其他" value="其他" />
          </el-select>
        </el-form-item>
        <el-form-item label-width="0">
          <div class="inline-row">
            <el-form-item :label="$t('label.priority')" prop="priority" class="inline-item">
              <el-radio-group v-model="editForm.priority">
                <el-radio-button label="高">高</el-radio-button>
                <el-radio-button label="中">中</el-radio-button>
                <el-radio-button label="低">低</el-radio-button>
              </el-radio-group>
            </el-form-item>
            <el-form-item :label="$t('label.feedbackchannel')" prop="feedbackchannel" class="inline-item">
              <el-select
                v-model="editForm.feedbackchannel"
                :placeholder="$t('placeholder.feedbackchannel')"
                clearable
                style="width: 160px"
              >
                <el-option label="微信群" value="微信群" />
                <el-option label="微信" value="微信" />
                <el-option label="电话" value="电话" />
                <el-option label="现场" value="现场" />
                <el-option label="钉钉群" value="钉钉群" />
                <el-option label="钉钉" value="钉钉" />
                <el-option label="其他" value="其他" />
              </el-select>
            </el-form-item>
          </div>
        </el-form-item>
        <el-form-item :label="$t('label.dept')" prop="department">
          <el-input
            v-model="editForm.department"
            :placeholder="$t('placeholder.dept')"
          />
        </el-form-item>
        <el-form-item :label="$t('label.name')" prop="submitter">
          <el-input
            v-model="editForm.submitter"
            :placeholder="$t('placeholder.name')"
          />
        </el-form-item>
        <el-form-item :label="$t('label.createat')" prop="createdat">
          <el-date-picker
            v-model="editForm.createdat"
            type="datetime"
            :placeholder="$t('placeholder.createat')"
            value-format="YYYY-MM-DD HH:mm:ss"
            format="YYYY-MM-DD HH:mm:ss"
            style="width: 100%"
          />
        </el-form-item>
        <el-form-item :label="$t('label.description')" prop="description">
          <div class="rich-editor">
            <Toolbar
              :editor="editorRef"
              :default-config="toolbarConfig"
              mode="default"
              style="border-bottom: 1px solid #dcdfe6"
            />
            <Editor
              v-model="editForm.description"
              :default-config="editorConfig"
              mode="default"
              style="height: 200px; overflow-y: auto"
              @on-created="handleEditorCreated"
              @custom-paste="handleEditorPasteImage"
            />
          </div>
        </el-form-item>
        <el-form-item :label="$t('label.attachment')">
          <el-upload
            v-model:file-list="editForm.files"
            :auto-upload="false"
            :limit="1"
            :on-exceed="handleAttachmentExceed"
            :on-change="handleAttachmentChange"
            :on-remove="handleAttachmentRemove"
          >
            <el-button type="primary" plain>{{ $t("btn.upload") }}</el-button>
            <template #tip>
              <div class="el-upload__tip">
                {{ $t("label.attachmentTip") }}
              </div>
            </template>
          </el-upload>
        </el-form-item>
      </el-form>
      <template #footer>
        <el-button @click="editVisible = false">{{ $t("common.cancel") }}</el-button>
        <el-button
          type="primary"
          :loading="editSubmitting"
          @click="submitEdit"
        >{{ $t("common.save") }}</el-button>
      </template>
    </el-dialog>

    <el-dialog
      v-model="previewVisible"
      :title="$t('btn.preview')"
      width="80%"
      top="5vh"
      destroy-on-close
      :before-close="closePreview"
    >
      <iframe
        v-if="previewType === 'pdf' && previewUrl"
        :src="previewUrl"
        class="preview-iframe"
      />
      <img
        v-else-if="previewType === 'image' && previewUrl"
        :src="previewUrl"
        class="preview-image"
      />
    </el-dialog>
  </div>
</template>

<script setup>
import dayjs from "dayjs";
import {
  nextTick,
  onBeforeUnmount,
  onMounted,
  reactive,
  ref,
  shallowRef,
} from "vue";
import { useRoute, useRouter } from "vue-router";
import { ArrowLeft, Document } from "@element-plus/icons-vue";
import { ElMessage } from "element-plus";
import { Editor, Toolbar } from "@wangeditor/editor-for-vue";
import "@wangeditor/editor/dist/css/style.css";
import { useI18n } from "vue-i18n";
import {
  getAdminOrderDetail,
  getAdminHospitals,
  getUploadFile,
  updateAdminOrder,
} from "@/service/modular/admin";

const { t: $t } = useI18n();
const route = useRoute();
const router = useRouter();
const loading = ref(false);
const detail = ref({});

const priorityType = (p) => (p === "高" ? "danger" : p === "中" ? "warning" : "info");
const statusType = (s) =>
  ({ 待处理: "warning", 处理中: "primary", 已完成: "success", 已取消: "info" })[s] || "info";

const loadDetail = async () => {
  loading.value = true;
  try {
    detail.value = await getAdminOrderDetail(route.params.id);
  } finally {
    loading.value = false;
  }
};

const goBack = () => router.back();

const previewVisible = ref(false);
const previewUrl = ref("");
const previewType = ref(""); // 'pdf' | 'image' | ''

const cleanupPreviewUrl = () => {
  if (previewUrl.value) {
    URL.revokeObjectURL(previewUrl.value);
    previewUrl.value = "";
  }
  previewType.value = "";
};

const closePreview = () => {
  previewVisible.value = false;
  cleanupPreviewUrl();
};

// 根据文件名/扩展名+blob 的 mime 判断文件类型
const getFileType = (fileName, blob) => {
  const name = String(fileName || "");
  const ext = name.split(".").pop()?.toLowerCase() || "";
  const mime = blob?.type || "";
  if (ext === "pdf" || mime === "application/pdf") return "pdf";
  if (
    ["jpg", "jpeg", "png", "gif", "bmp", "webp", "svg"].includes(ext) ||
    (mime && mime.startsWith("image/"))
  ) {
    return "image";
  }
  return "other";
};

// 浏览器直接下载 blob
const downloadBlob = (blob, fileName) => {
  const url = URL.createObjectURL(blob);
  const a = document.createElement("a");
  a.href = url;
  a.download = fileName || "download";
  document.body.appendChild(a);
  a.click();
  document.body.removeChild(a);
  setTimeout(() => URL.revokeObjectURL(url), 0);
};

const viewReport = async (attachmentPath, originalName) => {
  if (!attachmentPath) return;
  const path = String(attachmentPath);
  const downloadName = originalName || path;
  try {
    const blob = await getUploadFile(path);
    const type = getFileType(downloadName, blob);
    if (type === "pdf" || type === "image") {
      cleanupPreviewUrl();
      previewUrl.value = URL.createObjectURL(blob);
      previewType.value = type;
      previewVisible.value = true;
    } else {
      downloadBlob(blob, downloadName);
    }
  } catch (e) {
    ElMessage.error(e?.message || $t('msg.failed'));
  }
};

// ============== 编辑工单 ==============
const hospitals = ref([]);
// 颜色标签可选值（颜色 Hex 取自设计原型）
const colorOptions = [
  { label: "蓝", value: "#667eea" },
  { label: "绿", value: "#52c41a" },
  { label: "青", value: "#13c2c2" },
  { label: "紫", value: "#722ed1" },
  { label: "橙", value: "#fa8c16" },
  { label: "红", value: "#ff4d4f" },
];

const loadHospitals = async () => {
  try {
    const res = await getAdminHospitals({ page: 1, pageSize: 1000 });
    hospitals.value = res?.list || [];
  } catch (_) {
    hospitals.value = [];
  }
};

const editVisible = ref(false);
const editLoading = ref(false);
const editSubmitting = ref(false);
const editFormRef = ref();
// 已加载的原始附件 filePath 集合（用于判断用户是否需要保留原附件）
const editOriginalAttachments = ref([]);
// 颜色选择器
const editColorPickerVisible = ref(false);
const editColorPickerRef = ref();
const toggleEditColorPicker = () => {
  editColorPickerVisible.value = !editColorPickerVisible.value;
};
const selectEditColor = (val) => {
  editForm.colorTag = val;
  editColorPickerVisible.value = false;
};
const onDocClick = (e) => {
  if (!editColorPickerVisible.value) return;
  const el = editColorPickerRef.value;
  if (el && !el.contains(e.target)) {
    editColorPickerVisible.value = false;
  }
};

const editForm = reactive({
  hospitalId: undefined,
  title: "",
  serviceType: "",
  priority: "中",
  feedbackchannel: "",
  department: "",
  colorTag: "#667eea",
  description: "",
  submitter: "",
  createdat: "",
  files: [],
});

const MAX_FILE_SIZE = 50 * 1024 * 1024;
const MAX_PASTE_IMAGE_SIZE = 5 * 1024 * 1024;

// el-upload 事件：选文件后立即校验大小
const handleAttachmentChange = (file) => {
  if (file?.size > MAX_FILE_SIZE) {
    ElMessage.warning("文件不能超过 50MB");
    editForm.files = editForm.files.filter(
      (f) => f.uid !== file.uid || f.size <= MAX_FILE_SIZE,
    );
  }
};
const handleAttachmentExceed = () => {
  ElMessage.warning("只能上传 1 个文件");
};
const handleAttachmentRemove = () => {
  // el-upload 会自动从 v-model:file-list 移除
};

const editRules = {
  hospitalId: [
    {
      required: true,
      message: () => $t("msg.pleaseSelectHospital"),
      trigger: "change",
    },
  ],
  title: [
    {
      required: true,
      message: () => $t("msg.pleaseInputTitle"),
      trigger: "blur",
    },
  ],
  serviceType: [
    {
      required: true,
      message: () => $t("msg.pleaseSelectType"),
      trigger: "blur",
    },
  ],
  priority: [
    {
      required: true,
      message: () => $t("msg.pleaseSelectPriority"),
      trigger: "change",
    },
  ],
  feedbackchannel: [
    {
      required: true,
      message: () => $t("msg.pleaseSelectFeedbackChannel"),
      trigger: "change",
    },
  ],
  department: [
    {
      required: true,
      whitespace: true,
      message: () => $t("msg.pleaseInputDept"),
      trigger: "blur",
    },
  ],
  submitter: [
    {
      required: true,
      whitespace: true,
      message: () => $t("msg.pleaseInputName"),
      trigger: "blur",
    },
  ],
  description: [
    {
      required: true,
      validator: (_, value, callback) => {
        const hasImage = /<img\s/i.test(value || "");
        const text = (value || "")
          .replace(/<[^>]*>/g, "")
          .replace(/&nbsp;/gi, "")
          .trim();
        if (!text && !hasImage)
          return callback(new Error($t("msg.pleaseInputDescription")));
        callback();
      },
      trigger: "change",
    },
  ],
};

// 富文本编辑器配置
const editorRef = shallowRef();
const toolbarConfig = {
  excludeKeys: [
    "uploadImage",
    "insertVideo",
    "uploadVideo",
    "group-video",
    "emotion",
    "group-emoji",
  ],
};
// 从剪贴板中捞出图片文件（同时兼容 items 和 files 两种来源）
const collectPastedImages = (clipboardData) => {
  const files = [];
  const items = clipboardData?.items;
  if (items) {
    for (let i = 0; i < items.length; i++) {
      const item = items[i];
      if (item.kind === "file" && item.type?.startsWith("image/")) {
        const file = item.getAsFile();
        if (file) files.push(file);
      }
    }
  }
  if (files.length === 0 && clipboardData?.files) {
    for (let i = 0; i < clipboardData.files.length; i++) {
      const file = clipboardData.files[i];
      if (file.type?.startsWith("image/")) files.push(file);
    }
  }
  return files;
};

const handleEditorPasteImage = (editor, event) => {
  if (event.__wpsImageHandled) return;
  const imageFiles = collectPastedImages(event.clipboardData);
  if (imageFiles.length === 0) return;
  event.__wpsImageHandled = true;
  event.preventDefault();
  if (typeof event.stopPropagation === "function") event.stopPropagation();
  if (typeof event.stopImmediatePropagation === "function")
    event.stopImmediatePropagation();

  if (typeof editor.focus === "function") editor.focus();
  const savedSelection = editor.selection;

  imageFiles.forEach((file) => {
    if (file.size > MAX_PASTE_IMAGE_SIZE) {
      ElMessage.warning("粘贴的图片不能超过 5MB");
      return;
    }
    const reader = new FileReader();
    reader.onload = (e) => {
      const dataUrl = e.target?.result;
      if (!dataUrl) {
        ElMessage.error("图片读取失败");
        return;
      }
      try {
        if (savedSelection) editor.select(savedSelection);
      } catch (_) {
        if (typeof editor.focus === "function") editor.focus();
      }
      if (typeof editor.focus === "function") editor.focus();
      editor.dangerouslyInsertHtml(
        `<img src="${dataUrl}" style="max-width:100%;height:auto;" />`,
      );
      if (typeof editor.updateView === "function") editor.updateView();
    };
    reader.onerror = () => {
      ElMessage.error("图片处理失败");
    };
    reader.readAsDataURL(file);
  });
  return false;
};

const editorConfig = {
  placeholder: $t("placeholder.description"),
};
let pasteHandlerRef = null;
const handleEditorCreated = (editor) => {
  editorRef.value = editor;
  nextTick(() => {
    const root = typeof editor.$el === "function" ? editor.$el() : editor.$el;
    if (!root) return;
    const editable = root.querySelector?.('[contenteditable="true"]') || root;
    if (pasteHandlerRef) {
      editable.removeEventListener("paste", pasteHandlerRef, { capture: true });
    }
    pasteHandlerRef = (event) => handleEditorPasteImage(editor, event);
    editable.addEventListener("paste", pasteHandlerRef, { capture: true });
  });
};

// 从带路径分隔符的地址中截取最后的文件名
const getAttachmentFileName = (path) => {
  if (!path) return "";
  return String(path).replace(/\\/g, "/").split("/").pop() || "";
};

const resetEditForm = () => {
  Object.assign(editForm, {
    hospitalId: undefined,
    title: "",
    serviceType: "",
    priority: "中",
    feedbackchannel: "",
    department: "",
    colorTag: "#667eea",
    description: "",
    submitter: "",
    createdat: "",
    files: [],
  });
  editOriginalAttachments.value = [];
  editFormRef.value?.clearValidate();
};

const openEdit = () => {
  resetEditForm();
  editLoading.value = true;
  editVisible.value = true;
  // 延迟一帧等弹窗挂载，避免富文本在未挂载时设置 v-model 报错
  nextTick(async () => {
    const d = detail.value || {};
    editForm.hospitalId = hospitals.value.find((h) => h.name === d.hospitalName)?.id || undefined;
    editForm.title = d.title || "";
    editForm.serviceType = d.serviceType || "";
    editForm.priority = d.priority || "中";
    editForm.feedbackchannel = d.feedbackChannel || d.feedbackchannel || "";
    editForm.department = d.department || "";
    editForm.colorTag = d.colorTag || "#667eea";
    editForm.description = d.description || "";
    editForm.submitter = d.submitter || "";
    // 后端返回时间可能含 T，统一格式化为 YYYY-MM-DD HH:mm:ss 供 date-picker 回显
    editForm.createdat = d.createdAt
      ? dayjs(d.createdAt).format("YYYY-MM-DD HH:mm:ss")
      : "";
    // 附件回显：把详情里的第一个附件作为 el-upload 的"已上传"项展示
    const atts = d.attachments || [];
    editOriginalAttachments.value = atts.map((a) => a.filePath).filter(Boolean);
    if (atts.length) {
      const first = atts[0];
      const fileName = first.fileName || getAttachmentFileName(first.filePath);
      if (fileName) {
        editForm.files = [
          {
            uid: `attachment-${route.params.id}-0`,
            name: fileName,
            status: "success",
          },
        ];
      }
    }
    editLoading.value = false;
  });
};

const onEditClosed = () => {
  resetEditForm();
};

const submitEdit = async () => {
  editForm.department = (editForm.department || "").trim();
  editForm.submitter = (editForm.submitter || "").trim();
  await editFormRef.value.validate(async (valid) => {
    if (!valid) return;
    editSubmitting.value = true;
    try {
      const formData = new FormData();
      const { files, ...rest } = editForm;
      for (const [k, v] of Object.entries(rest)) {
        if (v !== undefined && v !== null && v !== "") {
          formData.append(k, v);
        }
      }
      // 仅在用户上传了新文件时才把 files 追加到 formData，
      // 这样后端看到 files 就视为替换附件，未带 files 则保留原附件
      const item = (files || [])[0];
      if (item) {
        const file = item.raw || (typeof item.size === "number" ? item : null);
        if (file) formData.append("files", file, item.name);
      }
      await updateAdminOrder(route.params.id, formData);
      ElMessage.success($t("msg.editSuccess"));
      editVisible.value = false;
      loadDetail();
    } finally {
      editSubmitting.value = false;
    }
  });
};

const removePasteListener = () => {
  const editor = editorRef.value;
  if (!editor || !pasteHandlerRef) return;
  const root = typeof editor.$el === "function" ? editor.$el() : editor.$el;
  if (!root) return;
  const editable = root.querySelector?.('[contenteditable="true"]') || root;
  editable.removeEventListener("paste", pasteHandlerRef, { capture: true });
};

onMounted(() => {
  loadDetail();
  loadHospitals();
  document.addEventListener("click", onDocClick);
});

onBeforeUnmount(() => {
  document.removeEventListener("click", onDocClick);
  removePasteListener();
  pasteHandlerRef = null;
  const editor = editorRef.value;
  if (editor == null) return;
  editor.destroy();
});
</script>

<style scoped lang="scss">
.page-header {
  margin-bottom: 12px;
  .page-title {
    font-size: 16px;
    font-weight: 600;
  }
}
.detail-card {
  .card-header {
    display: flex;
    align-items: center;
    gap: 8px;
    .title {
      font-size: 16px;
      font-weight: 600;
      margin-right: 8px;
    }
  }
  .section {
    margin-top: 20px;
    .section-title {
      font-size: 14px;
      font-weight: 600;
      color: #303133;
      margin-bottom: 10px;
    }
  }
  .html-content {
    background: #fafafa;
    padding: 12px;
    border-radius: 4px;
    min-height: 60px;
    line-height: 1.6;
  }
  .files {
    display: flex;
    flex-direction: column;
    gap: 8px;
    .file-item {
      display: inline-flex;
      align-items: center;
      gap: 4px;
    }
  }
  .log-title {
    font-weight: 600;
  }
  .log-remark {
    color: #606266;
    margin-top: 4px;
  }
}
.preview-iframe {
  width: 100%;
  height: 80vh;
  border: 0;
}
.preview-image {
  display: block;
  max-width: 100%;
  max-height: 80vh;
  margin: 0 auto;
  object-fit: contain;
}

.rich-editor {
  width: 100%;
  background: #fff;
  border-radius: 4px;
  // 用 box-shadow 模拟边框，避免 wangEditor 内部元素覆盖 border
  // box-shadow: 0 0 0 1px #dcdfe6 inset;
  border: 1px solid #dcdfe6;
  overflow: hidden;
}
.rich-editor :deep(.w-e-toolbar) {
  background: #fafafa;
  border-bottom: 1px solid #dcdfe6;
}
.rich-editor :deep(.w-e-text-container) {
  background: #fff;
}
// 标题 + 颜色标签
.title-row {
  display: flex;
  align-items: center;
  gap: 12px;
  width: 100%;
}
.title-row .el-input {
  flex: 1;
}
// 优先级 + 反馈渠道同一行展示
.inline-row {
  display: flex;
  flex-wrap: nowrap;
  align-items: center;
  gap: 0 24px;
  width: 100%;
}
.inline-row .inline-item {
  flex: 1 1 0;
  min-width: 0;
  margin-bottom: 0 !important;
}
.inline-row .inline-item :deep(.el-form-item__content) {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
}
.color-tag-picker {
  position: relative;
  flex-shrink: 0;
}
.color-tag-preview {
  width: 28px;
  height: 28px;
  border-radius: 6px;
  cursor: pointer;
  border: 2px solid #fff;
  box-shadow: 0 0 0 1px rgba(0, 0, 0, 0.1);
  transition:
    transform 0.2s ease,
    box-shadow 0.2s ease;
}
.color-tag-preview:hover {
  transform: scale(1.08);
}
.color-tag-preview.is-empty {
  background-image: linear-gradient(
    135deg,
    #f5f5f5 25%,
    transparent 25%,
    transparent 50%,
    #f5f5f5 50%,
    #f5f5f5 75%,
    transparent 75%
  );
  background-size: 8px 8px;
  box-shadow: 0 0 0 1px #dcdfe6;
}
.color-tag-dropdown {
  position: absolute;
  top: calc(100% + 8px);
  left: 0;
  z-index: 10;
  background: #fff;
  border-radius: 10px;
  padding: 12px 14px;
  box-shadow: 0 4px 16px rgba(0, 0, 0, 0.12);
  min-width: 180px;
}
.color-tag-title {
  font-size: 13px;
  font-weight: 600;
  color: #333;
  margin-bottom: 10px;
}
.color-tag-options {
  display: flex;
  gap: 8px;
  flex-wrap: wrap;
}
.color-tag-option {
  width: 24px;
  height: 24px;
  border-radius: 6px;
  cursor: pointer;
  border: 2px solid transparent;
  transition:
    transform 0.2s ease,
    border-color 0.2s ease;
}
.color-tag-option:hover {
  transform: scale(1.12);
}
.color-tag-option.active {
  border-color: #1890ff;
  box-shadow: 0 0 0 2px rgba(24, 144, 255, 0.2);
}
</style>
