diff --git a/.github/workflows/codecov.yml b/.github/workflows/codecov.yml
new file mode 100644
index 00000000..5ea69f33
--- /dev/null
+++ b/.github/workflows/codecov.yml
@@ -0,0 +1,39 @@
+# Unit Test Coverage Report
+name: Test Coverage
+
+on:
+ pull_request:
+ branches:
+ - feature/workflow
+ - develop
+ - main
+ - releases/**
+ - feature/**
+ paths:
+ - server/**
+ workflow_dispatch:
+
+jobs:
+ build:
+ name: Coverage
+ runs-on: ubuntu-latest
+
+ steps:
+ - name: Checkout
+ uses: actions/checkout@v4
+
+ - name: Setup node
+ uses: actions/setup-node@v4
+ with:
+ node-version: 20
+
+ - name: Install dependencies
+ run: cd server && npm install
+
+ - name: Run tests and collect coverage
+ run: cd server && npm run test:cov
+
+ - name: Upload coverage to Codecov
+ uses: codecov/codecov-action@v4
+ env:
+ CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }}
diff --git a/.github/workflows/server-lint.yml b/.github/workflows/server-lint.yml
new file mode 100644
index 00000000..dec0c544
--- /dev/null
+++ b/.github/workflows/server-lint.yml
@@ -0,0 +1,34 @@
+# Lint
+name: Server Lint
+
+on:
+ pull_request:
+ branches:
+ - feature/workflow
+ - develop
+ - main
+ - releases/**
+ - feature/**
+ paths:
+ - server/**
+ workflow_dispatch:
+
+jobs:
+ build:
+ name: Lint
+ runs-on: ubuntu-latest
+
+ steps:
+ - name: Checkout
+ uses: actions/checkout@v4
+
+ - name: Setup node
+ uses: actions/setup-node@v4
+ with:
+ node-version: 20
+
+ - name: Install dependencies
+ run: cd server && npm install
+
+ - name: Lint
+ run: cd server && npm run lint
diff --git a/.github/workflows/web-lint.yml b/.github/workflows/web-lint.yml
new file mode 100644
index 00000000..f0963789
--- /dev/null
+++ b/.github/workflows/web-lint.yml
@@ -0,0 +1,34 @@
+# Lint
+name: Web Lint
+
+on:
+ pull_request:
+ branches:
+ - feature/workflow
+ - develop
+ - main
+ - releases/**
+ - feature/**
+ paths:
+ - web/**
+ workflow_dispatch:
+
+jobs:
+ build:
+ name: Lint
+ runs-on: ubuntu-latest
+
+ steps:
+ - name: Checkout
+ uses: actions/checkout@v4
+
+ - name: Setup node
+ uses: actions/setup-node@v4
+ with:
+ node-version: 20
+
+ - name: Install dependencies
+ run: cd web && npm install
+
+ - name: Lint
+ run: cd web && npm run lint
diff --git a/web/package.json b/web/package.json
index 063fb000..1b879af2 100644
--- a/web/package.json
+++ b/web/package.json
@@ -4,8 +4,8 @@
"private": true,
"type": "module",
"scripts": {
- "serve": "vite",
- "dev": "vite",
+ "serve": "npm run dev",
+ "dev": "vite --open",
"build": "run-p type-check \"build-only {@}\" --",
"preview": "vite preview",
"build-only": "vite build",
@@ -45,6 +45,7 @@
"@vue/tsconfig": "^0.5.1",
"eslint": "^8.49.0",
"eslint-plugin-vue": "^9.17.0",
+ "husky": "^9.0.11",
"npm-run-all2": "^6.1.1",
"prettier": "^3.0.3",
"sass": "^1.72.0",
@@ -56,8 +57,19 @@
"vite-plugin-virtual-mpa": "^1.11.0",
"vue-tsc": "^1.8.27"
},
+ "husky": {
+ "hooks": {
+ "pre-commit": "lint-staged"
+ }
+ },
+ "lint-staged": {
+ "src/**/*.{.vue,.js,.jsx,.cjs,.mjs,.ts,.tsx,.cts,.mts}": [
+ "prettier --write",
+ "eslint --fix"
+ ]
+ },
"engines": {
- "node": ">=14.21.0",
- "npm": ">=6.14.17"
+ "node": ">=18.0.0",
+ "npm": ">=8.6.0"
}
}
diff --git a/web/src/management/config/dnd.ts b/web/src/management/config/dnd.ts
new file mode 100644
index 00000000..11039a41
--- /dev/null
+++ b/web/src/management/config/dnd.ts
@@ -0,0 +1 @@
+export const DND_GROUP = 'question'
\ No newline at end of file
diff --git a/web/src/management/pages/edit/components/MaterialGroup.vue b/web/src/management/pages/edit/components/MaterialGroup.vue
index e581ca5c..c3edfd9e 100644
--- a/web/src/management/pages/edit/components/MaterialGroup.vue
+++ b/web/src/management/pages/edit/components/MaterialGroup.vue
@@ -1,8 +1,9 @@
import { computed, defineComponent, ref, getCurrentInstance } from 'vue'
+import { useStore } from 'vuex'
import QuestionContainerB from '@/materials/questions/QuestionContainerB'
import QuestionWrapper from '@/management/pages/edit/components/QuestionWrapper.vue'
import draggable from 'vuedraggable'
import { filterQuestionPreviewData } from '@/management/utils/index'
+import { DND_GROUP } from '@/management/config/dnd'
export default defineComponent({
components: {
@@ -58,8 +61,15 @@ export default defineComponent({
}
},
setup(props, { emit }) {
- const renderData = computed(() => {
- return filterQuestionPreviewData(props.questionDataList)
+ const store = useStore()
+
+ const renderData = computed({
+ get () {
+ return filterQuestionPreviewData(props.questionDataList)
+ },
+ set (questionDataList) {
+ store.commit('edit/setQuestionDataList', questionDataList)
+ }
})
const handleSelect = (index) => {
emit('select', index)
@@ -89,6 +99,7 @@ export default defineComponent({
}
return {
+ DND_GROUP,
renderData,
handleSelect,
handleChangeSeq,
diff --git a/web/src/management/pages/edit/modules/questionModule/components/TypeList.vue b/web/src/management/pages/edit/modules/questionModule/components/TypeList.vue
index 652feb7f..e74100dd 100644
--- a/web/src/management/pages/edit/modules/questionModule/components/TypeList.vue
+++ b/web/src/management/pages/edit/modules/questionModule/components/TypeList.vue
@@ -6,58 +6,91 @@
:name="index"
:key="index"
>
-
-
-
-
-
+
+
+
+
{{ element.title }}
+
-
-
+
+
+
+
+
![]()
+
+
+
@@ -103,9 +136,10 @@ const onQuestionType = ({ type }) => {
background-color: $primary-color-light;
border: 1px solid $primary-color;
}
-
+
.text {
font-size: 12px;
+ user-select: none;
}
}
@@ -128,4 +162,64 @@ const onQuestionType = ({ type }) => {
.qtype-popper-2 {
transform: translateX(30px);
}
+// 设置拖拽到编辑区的样式
+.box .qtopic-item {
+ height: 2px;
+ width: 100%;
+ background-color: var(--primary-color);
+ * {
+ display: none;
+ }
+}
+
+@keyframes fadeIn {
+ from {
+ opacity: 0;
+ }
+ to {
+ opacity: 1;
+ }
+}
+
+.preview-popover {
+ position: fixed;
+ left: 390px;
+ z-index: 9;
+ width: 371px;
+ padding: 12px;
+ background: white;
+ border: 1px solid var(--el-border-color-light);
+ box-shadow: var(--el-box-shadow-light);
+ transform: translateY(-50%);
+ animation: fadeIn 100ms linear forwards;
+
+ .preview-image {
+ width: 100%;
+ object-fit: contain;
+ }
+
+ .preview-arrow {
+ position: absolute;
+ top: 50%;
+ left: -6px;
+ height: 10px;
+ width: 10px;
+ transform: translateX(-50%);
+ background: var(--el-border-color-light);
+ z-index: -1;
+ transform: rotate(-45deg);
+
+ &::before {
+ position: absolute;
+ content: "";
+ height: 10px;
+ width: 10px;
+ border: 1px solid var(--el-border-color-light);
+ background: #ffffff;
+ border-bottom-color: transparent;
+ border-right-color: transparent;
+ }
+
+ }
+}
diff --git a/web/src/management/store/edit/mutations.js b/web/src/management/store/edit/mutations.js
index fab89077..412b87a9 100644
--- a/web/src/management/store/edit/mutations.js
+++ b/web/src/management/store/edit/mutations.js
@@ -61,5 +61,8 @@ export default {
Object.keys(presets).forEach((key) => {
_set(state.schema, key, presets[key])
})
+ },
+ setQuestionDataList(state, data) {
+ state.schema.questionDataList = data
}
}
diff --git a/web/src/render/App.vue b/web/src/render/App.vue
index 6fba4f81..185c00c8 100644
--- a/web/src/render/App.vue
+++ b/web/src/render/App.vue
@@ -1,11 +1,21 @@
-
-
+
+
+
+
-