@@ -51,11 +51,11 @@
}}
填写结果
@@ -64,7 +64,7 @@
class="btn-op-item primary"
type="primary"
size="small"
- @click.stop="openCompanyResult(item, true)"
+ @click.stop="openAllThirdResult(item, true)"
>
查看
@@ -646,10 +646,12 @@
} from '@/utils/outbound-qc-pilot-view-sections'
import type { TagType } from '@/utils/status-tag-registry'
import {
+ ALL_THIRD_PARTY_CARD_TITLE,
+ allThirdPartyCardSubtitle,
buildTaskListDisplayItems,
companyGroupProgress,
uniqueAssigneeNames,
- type QcTaskListCompanyItem,
+ type QcTaskListAllThirdItem,
type QcTaskListDisplayItem
} from '@/utils/qc-company-task-group'
import QcCompanyTaskResultDialog from './QcCompanyTaskResultDialog.vue'
@@ -705,7 +707,7 @@
const displayItems = computed(() => buildTaskListDisplayItems(tableData.value))
function displayItemKey(item: QcTaskListDisplayItem, idx: number) {
- if (item.kind === 'company') return `company_${item.companyId || idx}`
+ if (item.kind === 'all-third') return `all_third_${idx}`
return item.task.id || `${item.kind}_${idx}`
}
@@ -715,35 +717,35 @@
return (row.assigneeUserIds || []).some((id) => String(id) === uid)
}
- function companyProgressText(item: QcTaskListCompanyItem) {
+ function companyProgressText(item: QcTaskListAllThirdItem) {
const { completed, total } = companyGroupProgress(item.tasks)
if (completed === 0) return '待执行'
return `${completed}/${total} 已完成`
}
- function companyProgressTagType(item: QcTaskListCompanyItem) {
+ function companyProgressTagType(item: QcTaskListAllThirdItem) {
const { completed, total } = companyGroupProgress(item.tasks)
if (total > 0 && completed === total) return 'success'
if (completed > 0) return 'warning'
return 'info'
}
- function canFillCompany(item: QcTaskListCompanyItem) {
+ function canFillAllThird(item: QcTaskListAllThirdItem) {
return item.tasks.some((t) => hasPrimaryTaskActions(t) && canFillResult(t))
}
const companyDialogVisible = ref(false)
const companyDialogReadonly = ref(false)
const companyDialogTasks = ref([])
- const companyDialogName = ref('')
+ const companyDialogName = ref(ALL_THIRD_PARTY_CARD_TITLE)
- function openCompanyResult(item: QcTaskListCompanyItem, forceReadonly?: boolean) {
+ function openAllThirdResult(item: QcTaskListAllThirdItem, forceReadonly?: boolean) {
let tasks = item.tasks
if (listMode.value === 'mine') {
tasks = tasks.filter((t) => isCurrentUserAssignee(t))
}
if (!tasks.length) return
- companyDialogName.value = item.companyName
+ companyDialogName.value = ALL_THIRD_PARTY_CARD_TITLE
companyDialogTasks.value = tasks
companyDialogReadonly.value =
forceReadonly === true ||
diff --git a/web-admin/src/views/research-donation/audit/index.vue b/web-admin/src/views/research-donation/audit/index.vue
index 30390789..b1c0b18c 100644
--- a/web-admin/src/views/research-donation/audit/index.vue
+++ b/web-admin/src/views/research-donation/audit/index.vue
@@ -419,6 +419,7 @@
formatProtocolDocBatchDeleteConfirm
} from '@/utils/protocol-doc-label'
import { maskIdCard } from '@/utils/mask-sensitive'
+ import { loadVoidTypeDict } from '@/utils/void-type-dict'
defineOptions({ name: 'ResearchDonationAudit' })
@@ -654,7 +655,8 @@
{ debounce: 300, deep: true }
)
- onMounted(() => {
+ onMounted(async () => {
+ await loadVoidTypeDict()
loadData()
})
diff --git a/web-admin/src/views/research-donation/list/index.vue b/web-admin/src/views/research-donation/list/index.vue
index ef5a3a9b..373f6d90 100644
--- a/web-admin/src/views/research-donation/list/index.vue
+++ b/web-admin/src/views/research-donation/list/index.vue
@@ -308,6 +308,7 @@
formatProtocolDocDeleteConfirm,
formatProtocolDocBatchDeleteConfirm
} from '@/utils/protocol-doc-label'
+ import { loadVoidTypeDict } from '@/utils/void-type-dict'
defineOptions({ name: 'ResearchDonationList' })
@@ -444,7 +445,8 @@
{ debounce: 300, deep: true }
)
- onMounted(() => {
+ onMounted(async () => {
+ await loadVoidTypeDict()
loadData()
})
diff --git a/生产环境信息/docker-compose.yml b/生产环境信息/docker-compose.yml
new file mode 100644
index 00000000..61de6635
--- /dev/null
+++ b/生产环境信息/docker-compose.yml
@@ -0,0 +1,145 @@
+# 中科兴皖 Docker Compose 部署(甲方交付版:使用预构建镜像,不含源码)
+#
+# 启动(在 deploy/docker 目录):
+# docker load -i ../../images/zkxw-app-images.tar
+# cp .env.example .env # 修改密码与镜像 tag
+# docker compose up -d
+#
+# 发版方本地从源码构建镜像:见 scripts/build-docker-images.sh
+# Profile 说明见 README.md
+
+name: zkxw
+
+services:
+ mysql:
+ profiles: [full]
+ image: mysql:5.7.36
+ # MySQL 5.7 无 arm64 镜像;Mac(M 芯片) 与甲方 x86 云主机均用 amd64(Mac 上由 Docker 模拟)
+ platform: linux/amd64
+ restart: unless-stopped
+ command: >
+ --character-set-server=utf8mb4
+ --collation-server=utf8mb4_unicode_ci
+ --explicit_defaults_for_timestamp=1
+ environment:
+ MYSQL_ROOT_PASSWORD: ${MYSQL_ROOT_PASSWORD}
+ MYSQL_DATABASE: zkxw
+ TZ: Asia/Shanghai
+ volumes:
+ - mysql_data:/var/lib/mysql
+ - ./mysql/init/01-init-db.sql:/docker-entrypoint-initdb.d/01-init-db.sql:ro
+ - ../../docs/sql/zkxw.sql:/docker-entrypoint-initdb.d/02-zkxw.sql:ro
+ healthcheck:
+ test: ['CMD', 'mysqladmin', 'ping', '-h', '127.0.0.1', '-p${MYSQL_ROOT_PASSWORD}']
+ interval: 10s
+ timeout: 5s
+ retries: 30
+ start_period: 60s
+
+ redis:
+ profiles: [full]
+ image: redis:7-alpine
+ platform: linux/amd64
+ restart: unless-stopped
+ command: redis-server --appendonly yes
+ volumes:
+ - redis_data:/data
+ healthcheck:
+ test: ['CMD', 'redis-cli', 'ping']
+ interval: 10s
+ timeout: 3s
+ retries: 10
+
+ minio:
+ profiles: [full, storage]
+ image: minio/minio:latest
+ platform: linux/amd64
+ restart: unless-stopped
+ command: server /data --console-address ":9001"
+ environment:
+ MINIO_ROOT_USER: ${MINIO_ACCESS_KEY}
+ MINIO_ROOT_PASSWORD: ${MINIO_SECRET_KEY}
+ TZ: Asia/Shanghai
+ volumes:
+ - minio_data:/data
+
+ minio-init:
+ profiles: [full, storage]
+ image: minio/mc:latest
+ platform: linux/amd64
+ depends_on:
+ minio:
+ condition: service_started
+ entrypoint: >
+ /bin/sh -c "
+ for i in 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15; do
+ mc alias set local http://minio:9000 $${MINIO_ACCESS_KEY} $${MINIO_SECRET_KEY} && break
+ sleep 2
+ done &&
+ mc mb --ignore-existing local/$${MINIO_BUCKET} &&
+ mc anonymous set download local/$${MINIO_BUCKET} &&
+ exit 0
+ "
+ environment:
+ MINIO_ACCESS_KEY: ${MINIO_ACCESS_KEY}
+ MINIO_SECRET_KEY: ${MINIO_SECRET_KEY}
+ MINIO_BUCKET: ${MINIO_BUCKET}
+ restart: 'no'
+
+ backend:
+ profiles: [app, full]
+ image: ${ZKXW_BACKEND_IMAGE:-zkxw-backend:latest}
+ platform: linux/amd64
+ restart: unless-stopped
+ env_file: .env
+ environment:
+ TZ: Asia/Shanghai
+ depends_on:
+ mysql:
+ condition: service_healthy
+ required: false
+ redis:
+ condition: service_healthy
+ required: false
+ minio-init:
+ condition: service_completed_successfully
+ required: false
+ volumes:
+ - /usr/share/zoneinfo/Asia/Shanghai:/etc/localtime:ro
+ - backend_uploads:/app/uploads
+ healthcheck:
+ test: ['CMD', 'python', '-c', "import urllib.request; urllib.request.urlopen('http://127.0.0.1:8111/health')"]
+ interval: 30s
+ timeout: 5s
+ retries: 5
+ start_period: 60s
+
+ web:
+ profiles: [app, full]
+ image: ${ZKXW_WEB_IMAGE:-zkxw-web:latest}
+ platform: linux/amd64
+ restart: unless-stopped
+ environment:
+ TZ: Asia/Shanghai
+ ports:
+ - '${HTTP_PORT:-8112}:80'
+ depends_on:
+ backend:
+ condition: service_healthy
+ minio:
+ condition: service_started
+ required: false
+ healthcheck:
+ test: ['CMD', 'wget', '-qO-', 'http://127.0.0.1/']
+ interval: 30s
+ timeout: 5s
+ retries: 5
+ start_period: 15s
+ volumes:
+ - /usr/share/zoneinfo/Asia/Shanghai:/etc/localtime:ro
+
+volumes:
+ mysql_data:
+ redis_data:
+ minio_data:
+ backend_uploads: