chore: 合并前端修复并调整 Docker 镜像源
This commit is contained in:
@@ -1,8 +1,8 @@
|
|||||||
import { computed, ref, type Ref, type ComputedRef } from 'vue'
|
import { computed, ref, type ComputedRef } from 'vue'
|
||||||
|
|
||||||
import { POLL_INTERVAL_MS, POLL_FAILURE_LIMIT } from './sessionConstants'
|
import { POLL_INTERVAL_MS, POLL_FAILURE_LIMIT } from './sessionConstants'
|
||||||
|
|
||||||
export interface UseSessionPollingOptions<T> {
|
export interface UseSessionPollingOptions {
|
||||||
/** Whether there is an active session – used as a guard inside the poll loop. */
|
/** Whether there is an active session – used as a guard inside the poll loop. */
|
||||||
hasSession: ComputedRef<boolean>
|
hasSession: ComputedRef<boolean>
|
||||||
/** Called on each poll tick (typically refreshSessionSummary). */
|
/** Called on each poll tick (typically refreshSessionSummary). */
|
||||||
@@ -13,7 +13,7 @@ export interface UseSessionPollingOptions<T> {
|
|||||||
pollWarningPrefix: string
|
pollWarningPrefix: string
|
||||||
}
|
}
|
||||||
|
|
||||||
export function useSessionPolling(options: UseSessionPollingOptions<unknown>) {
|
export function useSessionPolling(options: UseSessionPollingOptions) {
|
||||||
const { hasSession, onPollTick, pollWarningPrefix } = options
|
const { hasSession, onPollTick, pollWarningPrefix } = options
|
||||||
|
|
||||||
const pollWarningMessage = ref('')
|
const pollWarningMessage = ref('')
|
||||||
|
|||||||
@@ -102,7 +102,7 @@ export interface UseSessionPresentationOptions {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export function useSessionRoleFacts(options: UseSessionPresentationOptions) {
|
export function useSessionRoleFacts(options: UseSessionPresentationOptions) {
|
||||||
const { activityInfo, statusLabel, roleFactDefaults } = options
|
const { activityInfo, roleFactDefaults } = options
|
||||||
|
|
||||||
const roleFacts = computed<FactItem[]>(() => [
|
const roleFacts = computed<FactItem[]>(() => [
|
||||||
{
|
{
|
||||||
@@ -168,17 +168,17 @@ export function useSessionResultFacts(options: UseSessionResultFactsOptions) {
|
|||||||
// ---------------------------------------------------------------------------
|
// ---------------------------------------------------------------------------
|
||||||
|
|
||||||
export function buildRedeemBlockedReason(options: {
|
export function buildRedeemBlockedReason(options: {
|
||||||
detail: ComputedRef<unknown | null>
|
detail: Ref<unknown | null>
|
||||||
hasSession: ComputedRef<boolean>
|
hasSession: Ref<boolean>
|
||||||
loginTypeLabel: ComputedRef<string>
|
loginTypeLabel: Ref<string>
|
||||||
redeemLoading: ComputedRef<boolean>
|
redeemLoading: Ref<boolean>
|
||||||
roleReady: ComputedRef<boolean>
|
roleReady: Ref<boolean>
|
||||||
roleConfirmed: ComputedRef<boolean>
|
roleConfirmed: Ref<boolean>
|
||||||
sessionNotice: ComputedRef<string>
|
sessionNotice: Ref<string>
|
||||||
context: 'claim' | 'admin'
|
context: 'claim' | 'admin'
|
||||||
/** Claim-specific fields */
|
/** Claim-specific fields */
|
||||||
tokenStatus?: ComputedRef<string>
|
tokenStatus?: Ref<string>
|
||||||
requiresSupportReview?: ComputedRef<boolean>
|
requiresSupportReview?: Ref<boolean>
|
||||||
}): string {
|
}): string {
|
||||||
const {
|
const {
|
||||||
detail,
|
detail,
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import { computed, ref, watch, type Ref, type ComputedRef } from 'vue'
|
import { computed, ref, watch, type ComputedRef } from 'vue'
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Shared QR code display logic: renders the base64 QR image, tracks its
|
* Shared QR code display logic: renders the base64 QR image, tracks its
|
||||||
|
|||||||
@@ -22,7 +22,6 @@ import { notifyTencentActionError } from './tencent/session-errors'
|
|||||||
import {
|
import {
|
||||||
useSessionPolling,
|
useSessionPolling,
|
||||||
useSessionQrDisplay,
|
useSessionQrDisplay,
|
||||||
useSessionRoleFacts,
|
|
||||||
useSessionResultFacts,
|
useSessionResultFacts,
|
||||||
buildRedeemBlockedReason,
|
buildRedeemBlockedReason,
|
||||||
resolveTaskStatusLabel,
|
resolveTaskStatusLabel,
|
||||||
@@ -92,7 +91,7 @@ export function useAdminManualRedeemPage() {
|
|||||||
} = useSessionPolling({
|
} = useSessionPolling({
|
||||||
hasSession: computed(() => Boolean(task.value?.taskId && hasSession.value)),
|
hasSession: computed(() => Boolean(task.value?.taskId && hasSession.value)),
|
||||||
shouldKeepPolling: computed(() => shouldKeepPolling(detail.value)),
|
shouldKeepPolling: computed(() => shouldKeepPolling(detail.value)),
|
||||||
onPollTick: () => refreshSessionSummary({ silent: true }),
|
onPollTick: async () => { await refreshSessionSummary({ silent: true }) },
|
||||||
pollWarningPrefix: '人工兑换状态刷新失败',
|
pollWarningPrefix: '人工兑换状态刷新失败',
|
||||||
})
|
})
|
||||||
|
|
||||||
@@ -122,11 +121,6 @@ export function useAdminManualRedeemPage() {
|
|||||||
() => `请让客户使用${loginTypeLabel.value}扫码,并在手机上确认登录`,
|
() => `请让客户使用${loginTypeLabel.value}扫码,并在手机上确认登录`,
|
||||||
)
|
)
|
||||||
|
|
||||||
const { roleFacts } = useSessionRoleFacts({
|
|
||||||
activityInfo,
|
|
||||||
statusLabel,
|
|
||||||
roleFactDefaults: { nickname: '等待客户登录' },
|
|
||||||
})
|
|
||||||
|
|
||||||
const proofValue = computed(() => manualRequest.value?.proofValue || order.value?.platformOrderId || '-')
|
const proofValue = computed(() => manualRequest.value?.proofValue || order.value?.platformOrderId || '-')
|
||||||
|
|
||||||
@@ -230,9 +224,6 @@ export function useAdminManualRedeemPage() {
|
|||||||
})
|
})
|
||||||
|
|
||||||
// ── Helpers ────────────────────────────────────────────────────────
|
// ── Helpers ────────────────────────────────────────────────────────
|
||||||
function applyLoginTypeFromDetail(nextDetail: AdminManualRedeemDetail) {
|
|
||||||
loginType.value = syncLoginTypeFromDetail(nextDetail, loginType.value)
|
|
||||||
}
|
|
||||||
|
|
||||||
function restartPollingIfNeeded(nextDetail = detail.value) {
|
function restartPollingIfNeeded(nextDetail = detail.value) {
|
||||||
resetPolling()
|
resetPolling()
|
||||||
|
|||||||
@@ -17,7 +17,6 @@ import { notifyTencentActionError } from './tencent/session-errors'
|
|||||||
import {
|
import {
|
||||||
useSessionPolling,
|
useSessionPolling,
|
||||||
useSessionQrDisplay,
|
useSessionQrDisplay,
|
||||||
useSessionRoleFacts,
|
|
||||||
useSessionResultFacts,
|
useSessionResultFacts,
|
||||||
buildRedeemBlockedReason,
|
buildRedeemBlockedReason,
|
||||||
resolveTaskStatusLabel,
|
resolveTaskStatusLabel,
|
||||||
@@ -59,7 +58,7 @@ export function useClaimPage(token: string) {
|
|||||||
} = useSessionPolling({
|
} = useSessionPolling({
|
||||||
hasSession,
|
hasSession,
|
||||||
shouldKeepPolling: computed(() => shouldKeepPolling(detail.value)),
|
shouldKeepPolling: computed(() => shouldKeepPolling(detail.value)),
|
||||||
onPollTick: () => refreshSessionSummary({ silent: true }),
|
onPollTick: async () => { await refreshSessionSummary({ silent: true }) },
|
||||||
pollWarningPrefix: '领取状态刷新失败',
|
pollWarningPrefix: '领取状态刷新失败',
|
||||||
})
|
})
|
||||||
|
|
||||||
@@ -88,11 +87,6 @@ export function useClaimPage(token: string) {
|
|||||||
() => `请使用${loginTypeLabel.value}扫描二维码,并在手机上确认登录`,
|
() => `请使用${loginTypeLabel.value}扫描二维码,并在手机上确认登录`,
|
||||||
)
|
)
|
||||||
|
|
||||||
const { roleFacts } = useSessionRoleFacts({
|
|
||||||
activityInfo,
|
|
||||||
statusLabel,
|
|
||||||
roleFactDefaults: { nickname: '等待扫码登录' },
|
|
||||||
})
|
|
||||||
|
|
||||||
// Claim pages show 4 role facts, but original only had 3 (no area).
|
// Claim pages show 4 role facts, but original only had 3 (no area).
|
||||||
// Override roleFacts to match original exactly:
|
// Override roleFacts to match original exactly:
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import type { AdminFulfillmentBindingConfigItem, AdminObservedProductItem } from '@/types/admin'
|
import type { AdminObservedProductItem } from '@/types/admin'
|
||||||
|
|
||||||
export type EditableBinding = {
|
export type EditableBinding = {
|
||||||
id: string
|
id: string
|
||||||
|
|||||||
-1
@@ -3,7 +3,6 @@ import { reactive, ref } from 'vue'
|
|||||||
import { lookupAdminFulfillmentBindingOrder } from '@/services/admin'
|
import { lookupAdminFulfillmentBindingOrder } from '@/services/admin'
|
||||||
import type { AdminFulfillmentLookupItem, AdminFulfillmentLookupResult } from '@/types/admin'
|
import type { AdminFulfillmentLookupItem, AdminFulfillmentLookupResult } from '@/types/admin'
|
||||||
|
|
||||||
import type { ImportableProductCandidate } from './types'
|
|
||||||
import type { useFulfillmentBindings } from './useFulfillmentBindings'
|
import type { useFulfillmentBindings } from './useFulfillmentBindings'
|
||||||
|
|
||||||
export function useFulfillmentBindingsLookup(
|
export function useFulfillmentBindingsLookup(
|
||||||
|
|||||||
+1
-1
@@ -68,7 +68,7 @@ const emit = defineEmits<{
|
|||||||
</div>
|
</div>
|
||||||
<div class="section-action-group">
|
<div class="section-action-group">
|
||||||
<el-button round @click="emit('expandAll')">全部展开</el-button>
|
<el-button round @click="emit('expandAll')">全部展开</el-button>
|
||||||
<el-checkbox :model-value="enabled" @update:model-value="emit('update:enabled', $event)"
|
<el-checkbox :model-value="enabled" @update:model-value="emit('update:enabled', Boolean($event))"
|
||||||
>启用整条配置</el-checkbox
|
>启用整条配置</el-checkbox
|
||||||
>
|
>
|
||||||
<el-button round @click="emit('collapseReady')">收起已完成</el-button>
|
<el-button round @click="emit('collapseReady')">收起已完成</el-button>
|
||||||
|
|||||||
+1
@@ -528,6 +528,7 @@ export function useKuaishouCloudConfig() {
|
|||||||
// consume shops
|
// consume shops
|
||||||
getKuaishouConsumeShopOptions,
|
getKuaishouConsumeShopOptions,
|
||||||
findKuaishouConsumeShop,
|
findKuaishouConsumeShop,
|
||||||
|
getDefaultKuaishouConsumeShop,
|
||||||
formatKuaishouConsumeShopOption,
|
formatKuaishouConsumeShopOption,
|
||||||
handleKuaishouConsumeShopSelected,
|
handleKuaishouConsumeShopSelected,
|
||||||
// collapse
|
// collapse
|
||||||
|
|||||||
+3
-3
@@ -1,6 +1,6 @@
|
|||||||
import { computed, nextTick, reactive, ref } from 'vue'
|
import { computed, reactive, ref } from 'vue'
|
||||||
|
|
||||||
import { showError, showSuccess } from '@/lib/feedback'
|
import { showSuccess } from '@/lib/feedback'
|
||||||
import { fetchAdminNinetyoneOrders } from '@/services/admin'
|
import { fetchAdminNinetyoneOrders } from '@/services/admin'
|
||||||
import type { AdminNinetyoneOrderItem } from '@/types/admin'
|
import type { AdminNinetyoneOrderItem } from '@/types/admin'
|
||||||
|
|
||||||
@@ -39,7 +39,7 @@ export function useKuaishouCloudNinetyone(
|
|||||||
function createItemFromNinetyoneOrder(item: AdminNinetyoneOrderItem): EditableItem {
|
function createItemFromNinetyoneOrder(item: AdminNinetyoneOrderItem): EditableItem {
|
||||||
const productNo = String(item.productNo || '').trim()
|
const productNo = String(item.productNo || '').trim()
|
||||||
const productName = String(item.productName || productNo).trim()
|
const productName = String(item.productName || productNo).trim()
|
||||||
const defaultShop = config.getDefaultKuaishouConsumeShop ? config.findKuaishouConsumeShop() : null
|
const defaultShop = config.getDefaultKuaishouConsumeShop()
|
||||||
const shopOpts = config.getKuaishouConsumeShopOptions()
|
const shopOpts = config.getKuaishouConsumeShopOptions()
|
||||||
const shop = defaultShop || (shopOpts.length > 0 ? shopOpts[0] : null)
|
const shop = defaultShop || (shopOpts.length > 0 ? shopOpts[0] : null)
|
||||||
return {
|
return {
|
||||||
|
|||||||
@@ -32,7 +32,6 @@ const {
|
|||||||
singleDisplayValue,
|
singleDisplayValue,
|
||||||
bulkText,
|
bulkText,
|
||||||
skuSuggestionsLoading,
|
skuSuggestionsLoading,
|
||||||
inventorySkuSuggestions,
|
|
||||||
entrySkuSuggestions,
|
entrySkuSuggestions,
|
||||||
// actions
|
// actions
|
||||||
loadInventoryItems,
|
loadInventoryItems,
|
||||||
@@ -50,7 +49,6 @@ const {
|
|||||||
formatInventoryStatus,
|
formatInventoryStatus,
|
||||||
getGroupSuggestion,
|
getGroupSuggestion,
|
||||||
// utils
|
// utils
|
||||||
hasAdminRole,
|
|
||||||
formatAdminDateTime,
|
formatAdminDateTime,
|
||||||
} = useAdminInventory()
|
} = useAdminInventory()
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
@@ -6,8 +6,6 @@ import {
|
|||||||
fetchAdminInventoryItems,
|
fetchAdminInventoryItems,
|
||||||
fetchAdminInventorySkuSuggestions,
|
fetchAdminInventorySkuSuggestions,
|
||||||
importAdminInventoryItems,
|
importAdminInventoryItems,
|
||||||
invalidateAdminInventoryItem,
|
|
||||||
releaseAdminInventoryItem,
|
|
||||||
} from '@/services/admin'
|
} from '@/services/admin'
|
||||||
import type {
|
import type {
|
||||||
AdminInventoryItemListItem,
|
AdminInventoryItemListItem,
|
||||||
|
|||||||
@@ -190,6 +190,7 @@ const taskDetailLink = computed(() =>
|
|||||||
:copy-screenshot="copyScreenshot"
|
:copy-screenshot="copyScreenshot"
|
||||||
:download-screenshot="downloadScreenshot"
|
:download-screenshot="downloadScreenshot"
|
||||||
:open-preview="() => (screenshotPreviewVisible = true)"
|
:open-preview="() => (screenshotPreviewVisible = true)"
|
||||||
|
:screenshot-empty-title="screenshotEmptyTitle"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<TencentResultPanel
|
<TencentResultPanel
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ type Props = {
|
|||||||
copyScreenshot: () => void
|
copyScreenshot: () => void
|
||||||
downloadScreenshot: () => void
|
downloadScreenshot: () => void
|
||||||
openPreview: () => void
|
openPreview: () => void
|
||||||
|
screenshotEmptyTitle?: string
|
||||||
}
|
}
|
||||||
|
|
||||||
defineProps<Props>()
|
defineProps<Props>()
|
||||||
|
|||||||
+1
-1
@@ -1,7 +1,7 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
type TaskDetail = {
|
type TaskDetail = {
|
||||||
taskNo?: string
|
taskNo?: string
|
||||||
taskId?: string
|
taskId?: string | number
|
||||||
status?: string
|
status?: string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+1
-1
@@ -1,5 +1,5 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import type { EditableKuaishouEticketShop } from '../composables/types'
|
import type { EditableKuaishouEticketShop } from '../../composables/types'
|
||||||
import type {
|
import type {
|
||||||
AdminKuaishouEticketConsumeResult,
|
AdminKuaishouEticketConsumeResult,
|
||||||
AdminKuaishouEticketDetailResult,
|
AdminKuaishouEticketDetailResult,
|
||||||
|
|||||||
@@ -195,7 +195,7 @@ function mapEditableShop(item: AdminAgisoShopConfigItem): EditableShop {
|
|||||||
id: crypto.randomUUID(),
|
id: crypto.randomUUID(),
|
||||||
shopId: item.shopId,
|
shopId: item.shopId,
|
||||||
shopName: item.shopName,
|
shopName: item.shopName,
|
||||||
accessToken: item.accessToken,
|
accessToken: item.AccessToken,
|
||||||
enabled: item.enabled !== false,
|
enabled: item.enabled !== false,
|
||||||
messageTemplate: item.messageTemplate,
|
messageTemplate: item.messageTemplate,
|
||||||
autoDeliveryMessageTemplate: item.autoDeliveryMessageTemplate,
|
autoDeliveryMessageTemplate: item.autoDeliveryMessageTemplate,
|
||||||
|
|||||||
+5
-4
@@ -1,4 +1,4 @@
|
|||||||
import { ref, computed, type Ref } from 'vue'
|
import { ref, computed } from 'vue'
|
||||||
import { showError, showSuccess } from '@/lib/feedback'
|
import { showError, showSuccess } from '@/lib/feedback'
|
||||||
import {
|
import {
|
||||||
consumeAdminKuaishouEticket,
|
consumeAdminKuaishouEticket,
|
||||||
@@ -10,6 +10,7 @@ import type {
|
|||||||
AdminKuaishouEticketConsumeResult,
|
AdminKuaishouEticketConsumeResult,
|
||||||
AdminKuaishouEticketDetailResult,
|
AdminKuaishouEticketDetailResult,
|
||||||
AdminKuaishouEticketShopInfoResult,
|
AdminKuaishouEticketShopInfoResult,
|
||||||
|
AdminKuaishouEticketShopConfigItem,
|
||||||
AdminKuaishouEticketSourceConfig,
|
AdminKuaishouEticketSourceConfig,
|
||||||
} from '@/types/admin'
|
} from '@/types/admin'
|
||||||
import type { EditableKuaishouEticketShop } from './types'
|
import type { EditableKuaishouEticketShop } from './types'
|
||||||
@@ -68,11 +69,11 @@ export function useAdminKuaishouEticketPlatform() {
|
|||||||
filePath: string
|
filePath: string
|
||||||
source: {
|
source: {
|
||||||
baseUrl?: string
|
baseUrl?: string
|
||||||
shops: AdminKuaishouEticketShopInfoResult['shop'][]
|
shops: AdminKuaishouEticketShopConfigItem[]
|
||||||
}
|
}
|
||||||
}) {
|
}) {
|
||||||
kuaishouEticketFilePath.value = data.filePath
|
kuaishouEticketFilePath.value = data.filePath
|
||||||
shopManager.setShopsFromConfig(data.source.shops as any)
|
shopManager.setShopsFromConfig(data.source.shops)
|
||||||
kuaishouEticketForm.value = {
|
kuaishouEticketForm.value = {
|
||||||
baseUrl: data.source.baseUrl || 'https://s.kwaixiaodian.com',
|
baseUrl: data.source.baseUrl || 'https://s.kwaixiaodian.com',
|
||||||
selectedShopId: '',
|
selectedShopId: '',
|
||||||
@@ -106,7 +107,7 @@ export function useAdminKuaishouEticketPlatform() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function addKuaishouEticketShop() {
|
function addKuaishouEticketShop() {
|
||||||
const { newSelectedId } = shopManager.addKuaishouEticketShop(kuaishouEticketForm.value.selectedShopId)
|
const { newSelectedId } = shopManager.addKuaishouEticketShop()
|
||||||
setKuaishouEticketDebugShop(newSelectedId)
|
setKuaishouEticketDebugShop(newSelectedId)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+2
-2
@@ -1,12 +1,12 @@
|
|||||||
import { ref } from 'vue'
|
import { ref } from 'vue'
|
||||||
import type { EditableKuaishouEticketShop } from '../types'
|
import type { EditableKuaishouEticketShop } from './types'
|
||||||
import type { AdminKuaishouEticketShopConfigItem } from '@/types/admin'
|
import type { AdminKuaishouEticketShopConfigItem } from '@/types/admin'
|
||||||
|
|
||||||
export function useKuaishouEticketShopManager() {
|
export function useKuaishouEticketShopManager() {
|
||||||
const kuaishouEticketShops = ref<EditableKuaishouEticketShop[]>([])
|
const kuaishouEticketShops = ref<EditableKuaishouEticketShop[]>([])
|
||||||
const expandedKuaishouEticketShopIds = ref<string[]>([])
|
const expandedKuaishouEticketShopIds = ref<string[]>([])
|
||||||
|
|
||||||
function addKuaishouEticketShop(selectedShopId: string) {
|
function addKuaishouEticketShop() {
|
||||||
const shop = createEmptyKuaishouEticketShop()
|
const shop = createEmptyKuaishouEticketShop()
|
||||||
kuaishouEticketShops.value.unshift(shop)
|
kuaishouEticketShops.value.unshift(shop)
|
||||||
return { shop, newSelectedId: shop.id }
|
return { shop, newSelectedId: shop.id }
|
||||||
|
|||||||
@@ -1,18 +1,11 @@
|
|||||||
import { computed, onBeforeUnmount, ref } from 'vue'
|
import { computed, onBeforeUnmount, ref } from 'vue'
|
||||||
import { useRoute } from 'vue-router'
|
import { useRoute } from 'vue-router'
|
||||||
|
|
||||||
import { showError, showSuccess } from '@/lib/feedback'
|
import { showConfirm, showError, showSuccess } from '@/lib/feedback'
|
||||||
import {
|
import {
|
||||||
closeAdminTask,
|
|
||||||
completeAdminTaskManualDispatch,
|
completeAdminTaskManualDispatch,
|
||||||
fetchAdminTaskScreenshot,
|
fetchAdminTaskScreenshot,
|
||||||
fetchAdminTaskDetail,
|
fetchAdminTaskDetail,
|
||||||
markAdminTaskManualReview,
|
|
||||||
redeemAdminTaskAssisted,
|
|
||||||
regenerateAdminTaskClaimLink,
|
|
||||||
releaseAdminTaskInventoryBinding,
|
|
||||||
retryAdminTask,
|
|
||||||
confirmAdminTaskAssistedRole,
|
|
||||||
} from '@/services/admin'
|
} from '@/services/admin'
|
||||||
import type { AdminTaskActionResponse, AdminTaskDetail } from '@/types/admin'
|
import type { AdminTaskActionResponse, AdminTaskDetail } from '@/types/admin'
|
||||||
import { hasAdminRole } from '@/utils/admin-auth'
|
import { hasAdminRole } from '@/utils/admin-auth'
|
||||||
@@ -52,7 +45,7 @@ export function useAdminTaskDetail() {
|
|||||||
|
|
||||||
const claimLinkInvalid = computed(() => {
|
const claimLinkInvalid = computed(() => {
|
||||||
const tokenStatus = String(detail.value?.claimToken?.status || '').trim()
|
const tokenStatus = String(detail.value?.claimToken?.status || '').trim()
|
||||||
return Boolean(detail.value?.claimToken?.claimUrl) && tokenStatus && tokenStatus !== 'active'
|
return Boolean(detail.value?.claimToken?.claimUrl) && tokenStatus !== '' && tokenStatus !== 'active'
|
||||||
})
|
})
|
||||||
|
|
||||||
const screenshotSectionTitle = computed(() => {
|
const screenshotSectionTitle = computed(() => {
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
# Dev Dockerfile — single-stage, root, VNC/X11 + Playwright
|
# Dev Dockerfile — single-stage, root, VNC/X11 + Playwright
|
||||||
# For production, see backend.Dockerfile (multi-stage build)
|
# For production, see backend.Dockerfile (multi-stage build)
|
||||||
FROM node:22-bookworm
|
FROM docker.m.daocloud.io/library/node:22-bookworm
|
||||||
|
|
||||||
ARG DEBIAN_MIRROR=mirrors.cloud.tencent.com
|
ARG DEBIAN_MIRROR=mirrors.cloud.tencent.com
|
||||||
ARG NPM_REGISTRY=https://registry.npmmirror.com
|
ARG NPM_REGISTRY=https://registry.npmmirror.com
|
||||||
|
|||||||
@@ -7,7 +7,7 @@
|
|||||||
# ============================================================================
|
# ============================================================================
|
||||||
|
|
||||||
# --------------------------- Builder Stage -----------------------------------
|
# --------------------------- Builder Stage -----------------------------------
|
||||||
FROM node:22-bookworm AS builder
|
FROM docker.m.daocloud.io/library/node:22-bookworm AS builder
|
||||||
|
|
||||||
ARG DEBIAN_MIRROR=mirrors.cloud.tencent.com
|
ARG DEBIAN_MIRROR=mirrors.cloud.tencent.com
|
||||||
ARG NPM_REGISTRY=https://registry.npmmirror.com
|
ARG NPM_REGISTRY=https://registry.npmmirror.com
|
||||||
@@ -48,7 +48,7 @@ RUN --mount=type=cache,target=/ms-playwright-cache,sharing=locked \
|
|||||||
COPY apps/backend/ ./
|
COPY apps/backend/ ./
|
||||||
|
|
||||||
# --------------------------- Runtime Stage -----------------------------------
|
# --------------------------- Runtime Stage -----------------------------------
|
||||||
FROM node:22-bookworm-slim AS runtime
|
FROM docker.m.daocloud.io/library/node:22-bookworm-slim AS runtime
|
||||||
|
|
||||||
# HTTP mirrors — see builder note about OrbStack TLS
|
# HTTP mirrors — see builder note about OrbStack TLS
|
||||||
ENV DEBIAN_FRONTEND=noninteractive
|
ENV DEBIAN_FRONTEND=noninteractive
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
FROM caddy:2-alpine
|
FROM docker.m.daocloud.io/library/caddy:2-alpine
|
||||||
|
|
||||||
ENV TZ=Asia/Shanghai
|
ENV TZ=Asia/Shanghai
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
FROM node:22-bookworm AS builder
|
FROM docker.m.daocloud.io/library/node:22-bookworm AS builder
|
||||||
|
|
||||||
ARG NPM_REGISTRY=https://registry.npmmirror.com
|
ARG NPM_REGISTRY=https://registry.npmmirror.com
|
||||||
|
|
||||||
@@ -14,7 +14,7 @@ RUN --mount=type=cache,target=/root/.npm,sharing=locked \
|
|||||||
COPY apps/frontend/ ./
|
COPY apps/frontend/ ./
|
||||||
RUN npm run build
|
RUN npm run build
|
||||||
|
|
||||||
FROM caddy:2-alpine
|
FROM docker.m.daocloud.io/library/caddy:2-alpine
|
||||||
|
|
||||||
ENV TZ=Asia/Shanghai
|
ENV TZ=Asia/Shanghai
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
FROM python:3.11-slim-bookworm
|
FROM docker.m.daocloud.io/library/python:3.11-slim-bookworm
|
||||||
|
|
||||||
ARG DEBIAN_MIRROR=mirrors.cloud.tencent.com
|
ARG DEBIAN_MIRROR=mirrors.cloud.tencent.com
|
||||||
ARG PIP_INDEX_URL=https://mirrors.cloud.tencent.com/pypi/simple
|
ARG PIP_INDEX_URL=https://mirrors.cloud.tencent.com/pypi/simple
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
services:
|
services:
|
||||||
postgres:
|
postgres:
|
||||||
image: postgres:16-bookworm
|
image: docker.m.daocloud.io/library/postgres:16-bookworm
|
||||||
restart: unless-stopped
|
restart: unless-stopped
|
||||||
environment:
|
environment:
|
||||||
TZ: ${TZ:-Asia/Shanghai}
|
TZ: ${TZ:-Asia/Shanghai}
|
||||||
@@ -90,7 +90,7 @@ services:
|
|||||||
- "${TENCENT_BROWSER_NOVNC_PORT:-6080}:6080"
|
- "${TENCENT_BROWSER_NOVNC_PORT:-6080}:6080"
|
||||||
|
|
||||||
frontend:
|
frontend:
|
||||||
image: node:22-bookworm-slim
|
image: docker.m.daocloud.io/library/node:22-bookworm-slim
|
||||||
working_dir: /app
|
working_dir: /app
|
||||||
restart: unless-stopped
|
restart: unless-stopped
|
||||||
command: >-
|
command: >-
|
||||||
@@ -107,7 +107,7 @@ services:
|
|||||||
- frontend_node_modules:/app/node_modules
|
- frontend_node_modules:/app/node_modules
|
||||||
|
|
||||||
web:
|
web:
|
||||||
image: caddy:2-alpine
|
image: docker.m.daocloud.io/library/caddy:2-alpine
|
||||||
restart: unless-stopped
|
restart: unless-stopped
|
||||||
depends_on:
|
depends_on:
|
||||||
backend:
|
backend:
|
||||||
|
|||||||
+8
-3
@@ -1,6 +1,6 @@
|
|||||||
services:
|
services:
|
||||||
postgres:
|
postgres:
|
||||||
image: postgres:16-bookworm
|
image: docker.m.daocloud.io/library/postgres:16-bookworm
|
||||||
restart: unless-stopped
|
restart: unless-stopped
|
||||||
environment:
|
environment:
|
||||||
TZ: ${TZ:-Asia/Shanghai}
|
TZ: ${TZ:-Asia/Shanghai}
|
||||||
@@ -8,7 +8,11 @@ services:
|
|||||||
POSTGRES_USER: ${POSTGRES_USER:-postgres}
|
POSTGRES_USER: ${POSTGRES_USER:-postgres}
|
||||||
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD:-postgres}
|
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD:-postgres}
|
||||||
healthcheck:
|
healthcheck:
|
||||||
test: ["CMD-SHELL", "pg_isready -U ${POSTGRES_USER:-postgres} -d ${POSTGRES_DB:-order_site}"]
|
test:
|
||||||
|
[
|
||||||
|
"CMD-SHELL",
|
||||||
|
"pg_isready -U ${POSTGRES_USER:-postgres} -d ${POSTGRES_DB:-order_site}",
|
||||||
|
]
|
||||||
interval: 5s
|
interval: 5s
|
||||||
timeout: 5s
|
timeout: 5s
|
||||||
retries: 20
|
retries: 20
|
||||||
@@ -42,7 +46,8 @@ services:
|
|||||||
ocr-worker:
|
ocr-worker:
|
||||||
condition: service_healthy
|
condition: service_healthy
|
||||||
healthcheck:
|
healthcheck:
|
||||||
test: ["CMD-SHELL", "curl -fsS http://127.0.0.1:3000/health/ready || exit 1"]
|
test:
|
||||||
|
["CMD-SHELL", "curl -fsS http://127.0.0.1:3000/health/ready || exit 1"]
|
||||||
interval: 5s
|
interval: 5s
|
||||||
timeout: 5s
|
timeout: 5s
|
||||||
retries: 20
|
retries: 20
|
||||||
|
|||||||
Reference in New Issue
Block a user