Просмотр исходного кода

feat(web-admin): add mp webview CRM quote version history page.

Co-authored-by: Cursor <cursoragent@cursor.com>
wuzilong 2 недель назад
Родитель
Сommit
d0241ddbd4
1 измененных файлов с 139 добавлено и 5 удалено
  1. 139 5
      web-admin/src/views/m/crm/quote/versions.vue

+ 139 - 5
web-admin/src/views/m/crm/quote/versions.vue

@@ -1,17 +1,151 @@
 <template>
-  <MpWebviewShell>
+  <MpWebviewShell @ready="onShellReady">
     <header class="mp-wv-header">
       <div class="mp-wv-header__row">
-        <h1 class="mp-wv-header__title">{{ title }}</h1>
+        <button class="mp-wv-header__back" type="button" aria-label="返回详情" @click="goBack">
+          ←
+        </button>
+        <h1 class="mp-wv-header__title">版本历史</h1>
       </div>
+      <div v-if="quoteNo" class="mp-wv-header__sub">{{ quoteNo }}</div>
     </header>
+
+    <div
+      v-if="loading"
+      class="mp-plan-form-loading mp-plan-form-loading--page"
+      role="status"
+      aria-live="polite"
+      aria-busy="true"
+    >
+      <div class="mp-plan-form-loading__orb" aria-hidden="true">
+        <span class="mp-plan-form-loading__dot" />
+      </div>
+      <p class="mp-plan-form-loading__title">正在加载版本历史</p>
+      <p class="mp-plan-form-loading__desc">请稍候…</p>
+    </div>
+    <div v-else-if="errorText" class="mp-wv-empty">{{ errorText }}</div>
+    <div v-else-if="!versions.length" class="mp-wv-empty">
+      <div class="mp-wv-empty__title">暂无版本历史</div>
+    </div>
+    <div v-else class="mp-wv-detail-body">
+      <article
+        v-for="item in versions"
+        :key="String(item.id)"
+        class="mp-wv-card"
+        @click="goView(item)"
+      >
+        <div class="mp-wv-card__tags">
+          <el-tag v-if="Number(item.isLatest) === 1" type="success" size="small">当前版本</el-tag>
+          <el-tag v-else type="info" size="small">历史版本</el-tag>
+          <el-tag :type="statusTagType(item.status)" size="small">{{ statusLabel(item.status) }}</el-tag>
+        </div>
+        <div class="mp-wv-card__title">{{ item.version || '—' }}</div>
+        <div class="mp-wv-card__meta">{{ item.customerName || '—' }}</div>
+        <div class="mp-wv-card__meta">
+          {{ formatQuoteMoney(item.finalAmount ?? item.totalAmount) }} ·
+          {{ item.createTime || item.quoteDate || '—' }}
+        </div>
+      </article>
+    </div>
   </MpWebviewShell>
 </template>
+
 <script setup lang="ts">
-  import { computed } from 'vue'
-  import { useRoute } from 'vue-router'
+  import { ref } from 'vue'
+  import { useRoute, useRouter } from 'vue-router'
   import MpWebviewShell from '@/layouts/MpWebviewShell.vue'
+  import { getQuote, queryVersions } from '@/api/crm/quote'
+  import { formatQuoteMoney } from '@/utils/mp-crm-quote-card'
+  import { useDictStore } from '@/store/modules/dict'
   import '@/styles/mp-webview.scss'
+
   const route = useRoute()
-  const title = computed(() => String(route.meta.title || ''))
+  const router = useRouter()
+  const dictStore = useDictStore()
+
+  const loading = ref(true)
+  const errorText = ref('')
+  const quoteNo = ref('')
+  const versions = ref<any[]>([])
+
+  function statusLabel(status?: string) {
+    const raw = status || ''
+    return dictStore.getLabel('crm_quote_status', raw) || raw || '—'
+  }
+
+  function statusTagType(status?: string) {
+    return dictStore.getTagType('crm_quote_status', status || '') as
+      | 'success'
+      | 'warning'
+      | 'info'
+      | 'primary'
+      | 'danger'
+  }
+
+  async function loadVersions() {
+    const id = String(route.params.id || '').trim()
+    if (!id) {
+      errorText.value = '缺少报价单 ID'
+      loading.value = false
+      return
+    }
+    loading.value = true
+    try {
+      const detailRes = await getQuote(id)
+      const detail = ((detailRes as any)?.data ?? detailRes) || {}
+      quoteNo.value = String(detail.quoteNo || '')
+      if (!quoteNo.value) {
+        errorText.value = '无法获取报价单号'
+        versions.value = []
+        return
+      }
+      const verRes = await queryVersions(quoteNo.value)
+      const data = (verRes as any)?.data ?? verRes
+      versions.value = Array.isArray(data) ? data : data?.list || data?.rows || []
+      errorText.value = ''
+    } catch (error) {
+      versions.value = []
+      errorText.value = error instanceof Error ? error.message : '加载失败'
+    } finally {
+      loading.value = false
+    }
+  }
+
+  function goBack() {
+    const id = String(route.params.id || '').trim()
+    if (id) {
+      void router.push({ path: `/m/crm/quote/${id}`, query: { from: 'manage' } })
+      return
+    }
+    void router.back()
+  }
+
+  function goView(item: { id?: string | number }) {
+    const vid = String(item.id || '').trim()
+    if (!vid) return
+    void router.push({ path: `/m/crm/quote/${vid}`, query: { from: 'manage' } })
+  }
+
+  function onShellReady() {
+    void loadVersions()
+  }
 </script>
+
+<style scoped lang="scss">
+  .mp-wv-card {
+    margin-bottom: 10px;
+  }
+
+  .mp-wv-card__tags {
+    display: flex;
+    flex-wrap: wrap;
+    gap: 6px;
+    margin-bottom: 6px;
+  }
+
+  .mp-wv-card__title {
+    font-size: 15px;
+    font-weight: 700;
+    color: #087f57;
+  }
+</style>