fix
This commit is contained in:
49
AGENTS.md
49
AGENTS.md
@@ -8,6 +8,7 @@
|
|||||||
Vue 3 SPA with custom composables for data fetching. Element Plus for UI.
|
Vue 3 SPA with custom composables for data fetching. Element Plus for UI.
|
||||||
|
|
||||||
## Structure
|
## Structure
|
||||||
|
|
||||||
```
|
```
|
||||||
cloud-ui/src/
|
cloud-ui/src/
|
||||||
├── api/ # API modules (one per entity)
|
├── api/ # API modules (one per entity)
|
||||||
@@ -23,15 +24,16 @@ cloud-ui/src/
|
|||||||
|
|
||||||
## Key Hooks
|
## Key Hooks
|
||||||
|
|
||||||
| Hook | Purpose |
|
| Hook | Purpose |
|
||||||
|------|---------|
|
| ----------------------------------- | ---------------------------- |
|
||||||
| `useDict(type1, type2)` | Dictionary data with caching |
|
| `useDict(type1, type2)` | Dictionary data with caching |
|
||||||
| `useTable({ pageList, queryForm })` | Table + pagination |
|
| `useTable({ pageList, queryForm })` | Table + pagination |
|
||||||
| `useMessage()` | Toast notifications |
|
| `useMessage()` | Toast notifications |
|
||||||
| `useMessageBox()` | Confirm dialogs |
|
| `useMessageBox()` | Confirm dialogs |
|
||||||
| `useParam(type)` | System parameters |
|
| `useParam(type)` | System parameters |
|
||||||
|
|
||||||
## API Pattern
|
## API Pattern
|
||||||
|
|
||||||
```typescript
|
```typescript
|
||||||
import request from '/@/utils/request';
|
import request from '/@/utils/request';
|
||||||
|
|
||||||
@@ -43,6 +45,7 @@ export const delObj = (id) => request.post('/module/entity/delete', id);
|
|||||||
```
|
```
|
||||||
|
|
||||||
## Hooks Usage
|
## Hooks Usage
|
||||||
|
|
||||||
```typescript
|
```typescript
|
||||||
// Dictionary
|
// Dictionary
|
||||||
const { dict } = useDict('sex', 'status');
|
const { dict } = useDict('sex', 'status');
|
||||||
@@ -50,8 +53,8 @@ const { dict } = useDict('sex', 'status');
|
|||||||
|
|
||||||
// Table
|
// Table
|
||||||
const { tableData, loading, getData, pagination } = useTable({
|
const { tableData, loading, getData, pagination } = useTable({
|
||||||
pageList: fetchList,
|
pageList: fetchList,
|
||||||
queryForm: reactive({ name: '' })
|
queryForm: reactive({ name: '' }),
|
||||||
});
|
});
|
||||||
|
|
||||||
// Message
|
// Message
|
||||||
@@ -65,16 +68,17 @@ await msgBoxConfirm('确定删除?');
|
|||||||
|
|
||||||
## Constraints
|
## Constraints
|
||||||
|
|
||||||
| Rule | Details |
|
| Rule | Details |
|
||||||
|------|---------|
|
| --------------- | --------------------------------------------- |
|
||||||
| **Hardcoding** | NO hardcoded strings. Define constants first. |
|
| **Hardcoding** | NO hardcoded strings. Define constants first. |
|
||||||
| **Line width** | 150 chars (Prettier) |
|
| **Line width** | 150 chars (Prettier) |
|
||||||
| **Indentation** | Tabs (Prettier) |
|
| **Indentation** | Tabs (Prettier) |
|
||||||
| **Quotes** | Single quotes |
|
| **Quotes** | Single quotes |
|
||||||
| **API updates** | POST /edit (NOT PUT) |
|
| **API updates** | POST /edit (NOT PUT) |
|
||||||
| **API deletes** | POST /delete (NOT DELETE) |
|
| **API deletes** | POST /delete (NOT DELETE) |
|
||||||
|
|
||||||
## Commands
|
## Commands
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
npm run dev # Development server
|
npm run dev # Development server
|
||||||
npm run build # Production build
|
npm run build # Production build
|
||||||
@@ -84,15 +88,16 @@ npm run prettier # Format code
|
|||||||
|
|
||||||
## Non-Standard
|
## Non-Standard
|
||||||
|
|
||||||
| Location | Issue |
|
| Location | Issue |
|
||||||
|----------|-------|
|
| ------------------------------------ | ----------------------------- |
|
||||||
| `src/composables/` + `src/hooks/` | Both exist (prefer hooks/) |
|
| `src/composables/` + `src/hooks/` | Both exist (prefer hooks/) |
|
||||||
| `src/directive/` + `src/directives/` | Both exist |
|
| `src/directive/` + `src/directives/` | Both exist |
|
||||||
| `src/const/` | Named "const" not "constants" |
|
| `src/const/` | Named "const" not "constants" |
|
||||||
|
|
||||||
## ESLint Relaxed Rules
|
## ESLint Relaxed Rules
|
||||||
|
|
||||||
Many TypeScript rules are OFF:
|
Many TypeScript rules are OFF:
|
||||||
|
|
||||||
- `@typescript-eslint/no-explicit-any`: OFF
|
- `@typescript-eslint/no-explicit-any`: OFF
|
||||||
- `@typescript-eslint/explicit-function-return-type`: OFF
|
- `@typescript-eslint/explicit-function-return-type`: OFF
|
||||||
- `vue/require-default-prop`: OFF
|
- `vue/require-default-prop`: OFF
|
||||||
|
|||||||
@@ -1,14 +1,16 @@
|
|||||||
# 列显示/隐藏方案对比
|
# 列显示/隐藏方案对比
|
||||||
|
|
||||||
## 方案1:TableColumn 包装组件 ⭐推荐
|
## 方案 1:TableColumn 包装组件 ⭐ 推荐
|
||||||
|
|
||||||
### 优点
|
### 优点
|
||||||
|
|
||||||
- ✅ 使用简单,只需替换组件名
|
- ✅ 使用简单,只需替换组件名
|
||||||
- ✅ 完全兼容 `el-table-column` 的所有属性和插槽
|
- ✅ 完全兼容 `el-table-column` 的所有属性和插槽
|
||||||
- ✅ 代码清晰,易于维护
|
- ✅ 代码清晰,易于维护
|
||||||
- ✅ 无需修改现有代码结构
|
- ✅ 无需修改现有代码结构
|
||||||
|
|
||||||
### 缺点
|
### 缺点
|
||||||
|
|
||||||
- ❌ 需要创建一个新组件
|
- ❌ 需要创建一个新组件
|
||||||
- ❌ 需要在使用的地方 provide `isColumnVisible` 函数
|
- ❌ 需要在使用的地方 provide `isColumnVisible` 函数
|
||||||
|
|
||||||
@@ -16,43 +18,45 @@
|
|||||||
|
|
||||||
```vue
|
```vue
|
||||||
<template>
|
<template>
|
||||||
<el-table ref="tableRef">
|
<el-table ref="tableRef">
|
||||||
<TableColumnProvider :is-column-visible="isColumnVisible">
|
<TableColumnProvider :is-column-visible="isColumnVisible">
|
||||||
<!-- 替换 el-table-column 为 TableColumn,移除 v-if -->
|
<!-- 替换 el-table-column 为 TableColumn,移除 v-if -->
|
||||||
<TableColumn prop="tied" label="是否退休" width="100" align="center">
|
<TableColumn prop="tied" label="是否退休" width="100" align="center">
|
||||||
<template #default="scope">
|
<template #default="scope">
|
||||||
<StatusTag :value="scope.row.tied" :options="YES_OR_NO" />
|
<StatusTag :value="scope.row.tied" :options="YES_OR_NO" />
|
||||||
</template>
|
</template>
|
||||||
</TableColumn>
|
</TableColumn>
|
||||||
|
|
||||||
<TableColumn prop="nameNo" label="姓名/工号" min-width="150" align="center" fixed>
|
<TableColumn prop="nameNo" label="姓名/工号" min-width="150" align="center" fixed>
|
||||||
<template #default="scope">
|
<template #default="scope">
|
||||||
<TeacherNameNo :name="scope.row.realName" :no="scope.row.teacherNo" />
|
<TeacherNameNo :name="scope.row.realName" :no="scope.row.teacherNo" />
|
||||||
</template>
|
</template>
|
||||||
</TableColumn>
|
</TableColumn>
|
||||||
</TableColumnProvider>
|
</TableColumnProvider>
|
||||||
</el-table>
|
</el-table>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup>
|
<script setup>
|
||||||
import TableColumnProvider from '/@/components/TableColumn/Provider.vue'
|
import TableColumnProvider from '/@/components/TableColumn/Provider.vue';
|
||||||
import TableColumn from '/@/components/TableColumn/index.vue'
|
import TableColumn from '/@/components/TableColumn/index.vue';
|
||||||
|
|
||||||
const isColumnVisible = (propOrLabel) => {
|
const isColumnVisible = (propOrLabel) => {
|
||||||
return tableColumnControlRef.value?.isColumnVisible?.(propOrLabel) ?? true
|
return tableColumnControlRef.value?.isColumnVisible?.(propOrLabel) ?? true;
|
||||||
}
|
};
|
||||||
</script>
|
</script>
|
||||||
```
|
```
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 方案2:自定义指令 v-column-visible
|
## 方案 2:自定义指令 v-column-visible
|
||||||
|
|
||||||
### 优点
|
### 优点
|
||||||
|
|
||||||
- ✅ 可以保留 `el-table-column`
|
- ✅ 可以保留 `el-table-column`
|
||||||
- ✅ 使用相对简单
|
- ✅ 使用相对简单
|
||||||
|
|
||||||
### 缺点
|
### 缺点
|
||||||
|
|
||||||
- ❌ 仍然需要在每个列上添加指令
|
- ❌ 仍然需要在每个列上添加指令
|
||||||
- ❌ 实现较复杂,需要操作 DOM
|
- ❌ 实现较复杂,需要操作 DOM
|
||||||
- ❌ 可能不够优雅
|
- ❌ 可能不够优雅
|
||||||
@@ -61,26 +65,23 @@ const isColumnVisible = (propOrLabel) => {
|
|||||||
|
|
||||||
```vue
|
```vue
|
||||||
<template>
|
<template>
|
||||||
<el-table>
|
<el-table>
|
||||||
<el-table-column
|
<el-table-column v-column-visible="'tied'" prop="tied" label="是否退休" width="100" />
|
||||||
v-column-visible="'tied'"
|
</el-table>
|
||||||
prop="tied"
|
|
||||||
label="是否退休"
|
|
||||||
width="100"
|
|
||||||
/>
|
|
||||||
</el-table>
|
|
||||||
</template>
|
</template>
|
||||||
```
|
```
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 方案3:使用 computed 动态生成列配置
|
## 方案 3:使用 computed 动态生成列配置
|
||||||
|
|
||||||
### 优点
|
### 优点
|
||||||
|
|
||||||
- ✅ 最彻底,完全控制列的渲染
|
- ✅ 最彻底,完全控制列的渲染
|
||||||
- ✅ 性能最好(只渲染可见的列)
|
- ✅ 性能最好(只渲染可见的列)
|
||||||
|
|
||||||
### 缺点
|
### 缺点
|
||||||
|
|
||||||
- ❌ 需要重构现有代码,改动较大
|
- ❌ 需要重构现有代码,改动较大
|
||||||
- ❌ 需要将列配置抽离出来
|
- ❌ 需要将列配置抽离出来
|
||||||
- ❌ 插槽处理较复杂
|
- ❌ 插槽处理较复杂
|
||||||
@@ -89,40 +90,38 @@ const isColumnVisible = (propOrLabel) => {
|
|||||||
|
|
||||||
```vue
|
```vue
|
||||||
<template>
|
<template>
|
||||||
<el-table>
|
<el-table>
|
||||||
<component
|
<component v-for="col in visibleColumns" :is="col.component" v-bind="col.props">
|
||||||
v-for="col in visibleColumns"
|
<template v-if="col.slots" #[slotName]="slotProps" v-for="(slot, slotName) in col.slots">
|
||||||
:is="col.component"
|
<component :is="slot" v-bind="slotProps" />
|
||||||
v-bind="col.props"
|
</template>
|
||||||
>
|
</component>
|
||||||
<template v-if="col.slots" #[slotName]="slotProps" v-for="(slot, slotName) in col.slots">
|
</el-table>
|
||||||
<component :is="slot" v-bind="slotProps" />
|
|
||||||
</template>
|
|
||||||
</component>
|
|
||||||
</el-table>
|
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup>
|
<script setup>
|
||||||
const columns = [
|
const columns = [
|
||||||
{ prop: 'tied', label: '是否退休', component: 'el-table-column', slots: { default: StatusTag } },
|
{ prop: 'tied', label: '是否退休', component: 'el-table-column', slots: { default: StatusTag } },
|
||||||
// ...
|
// ...
|
||||||
]
|
];
|
||||||
|
|
||||||
const visibleColumns = computed(() => {
|
const visibleColumns = computed(() => {
|
||||||
return columns.filter(col => isColumnVisible(col.prop || col.label))
|
return columns.filter((col) => isColumnVisible(col.prop || col.label));
|
||||||
})
|
});
|
||||||
</script>
|
</script>
|
||||||
```
|
```
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 方案4:在 el-table 层面使用 provide + 自动处理
|
## 方案 4:在 el-table 层面使用 provide + 自动处理
|
||||||
|
|
||||||
### 优点
|
### 优点
|
||||||
|
|
||||||
- ✅ 在表格层面统一处理
|
- ✅ 在表格层面统一处理
|
||||||
- ✅ 子组件自动继承
|
- ✅ 子组件自动继承
|
||||||
|
|
||||||
### 缺点
|
### 缺点
|
||||||
|
|
||||||
- ❌ 实现最复杂
|
- ❌ 实现最复杂
|
||||||
- ❌ 需要修改 Element Plus 的渲染逻辑
|
- ❌ 需要修改 Element Plus 的渲染逻辑
|
||||||
- ❌ 可能影响性能
|
- ❌ 可能影响性能
|
||||||
@@ -131,21 +130,23 @@ const visibleColumns = computed(() => {
|
|||||||
|
|
||||||
## 推荐方案
|
## 推荐方案
|
||||||
|
|
||||||
**推荐使用方案1(TableColumn 包装组件)**,因为:
|
**推荐使用方案 1(TableColumn 包装组件)**,因为:
|
||||||
|
|
||||||
1. 使用最简单,只需替换组件名
|
1. 使用最简单,只需替换组件名
|
||||||
2. 完全兼容现有代码
|
2. 完全兼容现有代码
|
||||||
3. 易于维护和理解
|
3. 易于维护和理解
|
||||||
4. 性能良好
|
4. 性能良好
|
||||||
|
|
||||||
## 迁移步骤(方案1)
|
## 迁移步骤(方案 1)
|
||||||
|
|
||||||
1. 导入组件:
|
1. 导入组件:
|
||||||
|
|
||||||
```vue
|
```vue
|
||||||
import TableColumnProvider from '/@/components/TableColumn/Provider.vue'
|
import TableColumnProvider from '/@/components/TableColumn/Provider.vue' import TableColumn from '/@/components/TableColumn/index.vue'
|
||||||
import TableColumn from '/@/components/TableColumn/index.vue'
|
|
||||||
```
|
```
|
||||||
|
|
||||||
2. 用 `TableColumnProvider` 包裹所有列,并传入 `isColumnVisible`:
|
2. 用 `TableColumnProvider` 包裹所有列,并传入 `isColumnVisible`:
|
||||||
|
|
||||||
```vue
|
```vue
|
||||||
<TableColumnProvider :is-column-visible="isColumnVisible">
|
<TableColumnProvider :is-column-visible="isColumnVisible">
|
||||||
<!-- 所有列 -->
|
<!-- 所有列 -->
|
||||||
@@ -153,6 +154,7 @@ import TableColumn from '/@/components/TableColumn/index.vue'
|
|||||||
```
|
```
|
||||||
|
|
||||||
3. 将所有 `el-table-column` 替换为 `TableColumn`,并移除 `v-if`:
|
3. 将所有 `el-table-column` 替换为 `TableColumn`,并移除 `v-if`:
|
||||||
|
|
||||||
```vue
|
```vue
|
||||||
<!-- 之前 -->
|
<!-- 之前 -->
|
||||||
<el-table-column v-if="isColumnVisible('tied')" prop="tied" label="是否退休" />
|
<el-table-column v-if="isColumnVisible('tied')" prop="tied" label="是否退休" />
|
||||||
@@ -160,4 +162,3 @@ import TableColumn from '/@/components/TableColumn/index.vue'
|
|||||||
<!-- 之后 -->
|
<!-- 之后 -->
|
||||||
<TableColumn prop="tied" label="是否退休" />
|
<TableColumn prop="tied" label="是否退休" />
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|||||||
140
auto-imports.d.ts
vendored
140
auto-imports.d.ts
vendored
@@ -1,73 +1,73 @@
|
|||||||
// Generated by 'unplugin-auto-import'
|
// Generated by 'unplugin-auto-import'
|
||||||
export {}
|
export {};
|
||||||
declare global {
|
declare global {
|
||||||
const EffectScope: typeof import('vue')['EffectScope']
|
const EffectScope: typeof import('vue')['EffectScope'];
|
||||||
const acceptHMRUpdate: typeof import('pinia')['acceptHMRUpdate']
|
const acceptHMRUpdate: typeof import('pinia')['acceptHMRUpdate'];
|
||||||
const computed: typeof import('vue')['computed']
|
const computed: typeof import('vue')['computed'];
|
||||||
const createApp: typeof import('vue')['createApp']
|
const createApp: typeof import('vue')['createApp'];
|
||||||
const createPinia: typeof import('pinia')['createPinia']
|
const createPinia: typeof import('pinia')['createPinia'];
|
||||||
const customRef: typeof import('vue')['customRef']
|
const customRef: typeof import('vue')['customRef'];
|
||||||
const defineAsyncComponent: typeof import('vue')['defineAsyncComponent']
|
const defineAsyncComponent: typeof import('vue')['defineAsyncComponent'];
|
||||||
const defineComponent: typeof import('vue')['defineComponent']
|
const defineComponent: typeof import('vue')['defineComponent'];
|
||||||
const defineStore: typeof import('pinia')['defineStore']
|
const defineStore: typeof import('pinia')['defineStore'];
|
||||||
const effectScope: typeof import('vue')['effectScope']
|
const effectScope: typeof import('vue')['effectScope'];
|
||||||
const getActivePinia: typeof import('pinia')['getActivePinia']
|
const getActivePinia: typeof import('pinia')['getActivePinia'];
|
||||||
const getCurrentInstance: typeof import('vue')['getCurrentInstance']
|
const getCurrentInstance: typeof import('vue')['getCurrentInstance'];
|
||||||
const getCurrentScope: typeof import('vue')['getCurrentScope']
|
const getCurrentScope: typeof import('vue')['getCurrentScope'];
|
||||||
const h: typeof import('vue')['h']
|
const h: typeof import('vue')['h'];
|
||||||
const inject: typeof import('vue')['inject']
|
const inject: typeof import('vue')['inject'];
|
||||||
const isProxy: typeof import('vue')['isProxy']
|
const isProxy: typeof import('vue')['isProxy'];
|
||||||
const isReactive: typeof import('vue')['isReactive']
|
const isReactive: typeof import('vue')['isReactive'];
|
||||||
const isReadonly: typeof import('vue')['isReadonly']
|
const isReadonly: typeof import('vue')['isReadonly'];
|
||||||
const isRef: typeof import('vue')['isRef']
|
const isRef: typeof import('vue')['isRef'];
|
||||||
const mapActions: typeof import('pinia')['mapActions']
|
const mapActions: typeof import('pinia')['mapActions'];
|
||||||
const mapGetters: typeof import('pinia')['mapGetters']
|
const mapGetters: typeof import('pinia')['mapGetters'];
|
||||||
const mapState: typeof import('pinia')['mapState']
|
const mapState: typeof import('pinia')['mapState'];
|
||||||
const mapStores: typeof import('pinia')['mapStores']
|
const mapStores: typeof import('pinia')['mapStores'];
|
||||||
const mapWritableState: typeof import('pinia')['mapWritableState']
|
const mapWritableState: typeof import('pinia')['mapWritableState'];
|
||||||
const markRaw: typeof import('vue')['markRaw']
|
const markRaw: typeof import('vue')['markRaw'];
|
||||||
const nextTick: typeof import('vue')['nextTick']
|
const nextTick: typeof import('vue')['nextTick'];
|
||||||
const onActivated: typeof import('vue')['onActivated']
|
const onActivated: typeof import('vue')['onActivated'];
|
||||||
const onBeforeMount: typeof import('vue')['onBeforeMount']
|
const onBeforeMount: typeof import('vue')['onBeforeMount'];
|
||||||
const onBeforeRouteLeave: typeof import('vue-router')['onBeforeRouteLeave']
|
const onBeforeRouteLeave: typeof import('vue-router')['onBeforeRouteLeave'];
|
||||||
const onBeforeRouteUpdate: typeof import('vue-router')['onBeforeRouteUpdate']
|
const onBeforeRouteUpdate: typeof import('vue-router')['onBeforeRouteUpdate'];
|
||||||
const onBeforeUnmount: typeof import('vue')['onBeforeUnmount']
|
const onBeforeUnmount: typeof import('vue')['onBeforeUnmount'];
|
||||||
const onBeforeUpdate: typeof import('vue')['onBeforeUpdate']
|
const onBeforeUpdate: typeof import('vue')['onBeforeUpdate'];
|
||||||
const onDeactivated: typeof import('vue')['onDeactivated']
|
const onDeactivated: typeof import('vue')['onDeactivated'];
|
||||||
const onErrorCaptured: typeof import('vue')['onErrorCaptured']
|
const onErrorCaptured: typeof import('vue')['onErrorCaptured'];
|
||||||
const onMounted: typeof import('vue')['onMounted']
|
const onMounted: typeof import('vue')['onMounted'];
|
||||||
const onRenderTracked: typeof import('vue')['onRenderTracked']
|
const onRenderTracked: typeof import('vue')['onRenderTracked'];
|
||||||
const onRenderTriggered: typeof import('vue')['onRenderTriggered']
|
const onRenderTriggered: typeof import('vue')['onRenderTriggered'];
|
||||||
const onScopeDispose: typeof import('vue')['onScopeDispose']
|
const onScopeDispose: typeof import('vue')['onScopeDispose'];
|
||||||
const onServerPrefetch: typeof import('vue')['onServerPrefetch']
|
const onServerPrefetch: typeof import('vue')['onServerPrefetch'];
|
||||||
const onUnmounted: typeof import('vue')['onUnmounted']
|
const onUnmounted: typeof import('vue')['onUnmounted'];
|
||||||
const onUpdated: typeof import('vue')['onUpdated']
|
const onUpdated: typeof import('vue')['onUpdated'];
|
||||||
const provide: typeof import('vue')['provide']
|
const provide: typeof import('vue')['provide'];
|
||||||
const reactive: typeof import('vue')['reactive']
|
const reactive: typeof import('vue')['reactive'];
|
||||||
const readonly: typeof import('vue')['readonly']
|
const readonly: typeof import('vue')['readonly'];
|
||||||
const ref: typeof import('vue')['ref']
|
const ref: typeof import('vue')['ref'];
|
||||||
const resolveComponent: typeof import('vue')['resolveComponent']
|
const resolveComponent: typeof import('vue')['resolveComponent'];
|
||||||
const resolveDirective: typeof import('vue')['resolveDirective']
|
const resolveDirective: typeof import('vue')['resolveDirective'];
|
||||||
const setActivePinia: typeof import('pinia')['setActivePinia']
|
const setActivePinia: typeof import('pinia')['setActivePinia'];
|
||||||
const setMapStoreSuffix: typeof import('pinia')['setMapStoreSuffix']
|
const setMapStoreSuffix: typeof import('pinia')['setMapStoreSuffix'];
|
||||||
const shallowReactive: typeof import('vue')['shallowReactive']
|
const shallowReactive: typeof import('vue')['shallowReactive'];
|
||||||
const shallowReadonly: typeof import('vue')['shallowReadonly']
|
const shallowReadonly: typeof import('vue')['shallowReadonly'];
|
||||||
const shallowRef: typeof import('vue')['shallowRef']
|
const shallowRef: typeof import('vue')['shallowRef'];
|
||||||
const storeToRefs: typeof import('pinia')['storeToRefs']
|
const storeToRefs: typeof import('pinia')['storeToRefs'];
|
||||||
const toRaw: typeof import('vue')['toRaw']
|
const toRaw: typeof import('vue')['toRaw'];
|
||||||
const toRef: typeof import('vue')['toRef']
|
const toRef: typeof import('vue')['toRef'];
|
||||||
const toRefs: typeof import('vue')['toRefs']
|
const toRefs: typeof import('vue')['toRefs'];
|
||||||
const triggerRef: typeof import('vue')['triggerRef']
|
const triggerRef: typeof import('vue')['triggerRef'];
|
||||||
const unref: typeof import('vue')['unref']
|
const unref: typeof import('vue')['unref'];
|
||||||
const useAttrs: typeof import('vue')['useAttrs']
|
const useAttrs: typeof import('vue')['useAttrs'];
|
||||||
const useCssModule: typeof import('vue')['useCssModule']
|
const useCssModule: typeof import('vue')['useCssModule'];
|
||||||
const useCssVars: typeof import('vue')['useCssVars']
|
const useCssVars: typeof import('vue')['useCssVars'];
|
||||||
const useLink: typeof import('vue-router')['useLink']
|
const useLink: typeof import('vue-router')['useLink'];
|
||||||
const useRoute: typeof import('vue-router')['useRoute']
|
const useRoute: typeof import('vue-router')['useRoute'];
|
||||||
const useRouter: typeof import('vue-router')['useRouter']
|
const useRouter: typeof import('vue-router')['useRouter'];
|
||||||
const useSlots: typeof import('vue')['useSlots']
|
const useSlots: typeof import('vue')['useSlots'];
|
||||||
const watch: typeof import('vue')['watch']
|
const watch: typeof import('vue')['watch'];
|
||||||
const watchEffect: typeof import('vue')['watchEffect']
|
const watchEffect: typeof import('vue')['watchEffect'];
|
||||||
const watchPostEffect: typeof import('vue')['watchPostEffect']
|
const watchPostEffect: typeof import('vue')['watchPostEffect'];
|
||||||
const watchSyncEffect: typeof import('vue')['watchSyncEffect']
|
const watchSyncEffect: typeof import('vue')['watchSyncEffect'];
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,77 +1,89 @@
|
|||||||
<!DOCTYPE html>
|
<!DOCTYPE html>
|
||||||
<html>
|
<html>
|
||||||
<head>
|
<head>
|
||||||
<meta charset="UTF-8">
|
<meta charset="UTF-8" />
|
||||||
<title>${ENV, var="JOB_NAME"}-第${BUILD_NUMBER}次构建日志</title>
|
<title>${ENV, var="JOB_NAME"}-第${BUILD_NUMBER}次构建日志</title>
|
||||||
</head>
|
</head>
|
||||||
|
|
||||||
<body leftmargin="8" marginwidth="0" topmargin="8" marginheight="4"
|
<body leftmargin="8" marginwidth="0" topmargin="8" marginheight="4" offset="0">
|
||||||
offset="0">
|
<table width="95%" cellpadding="0" cellspacing="0" style="font-size: 11pt; font-family: Tahoma, Arial, Helvetica, sans-serif">
|
||||||
<table width="95%" cellpadding="0" cellspacing="0"
|
<tr>
|
||||||
style="font-size: 11pt; font-family: Tahoma, Arial, Helvetica, sans-serif">
|
<td>(本邮件是程序自动下发的,请勿回复!)</td>
|
||||||
<tr>
|
</tr>
|
||||||
<td>(本邮件是程序自动下发的,请勿回复!)</td>
|
<tr>
|
||||||
</tr>
|
<td>
|
||||||
<tr>
|
<h2>
|
||||||
<td><h2>
|
<font color="#FF0000">构建结果 - ${BUILD_STATUS}</font>
|
||||||
<font color="#FF0000">构建结果 - ${BUILD_STATUS}</font>
|
</h2>
|
||||||
</h2></td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td><br />
|
<td>
|
||||||
<b><font color="#0B610B">构建信息</font></b>
|
<br />
|
||||||
<hr size="2" width="100%" align="center" /></td>
|
<b><font color="#0B610B">构建信息</font></b>
|
||||||
</tr>
|
<hr size="2" width="100%" align="center" />
|
||||||
<tr>
|
</td>
|
||||||
<td>
|
</tr>
|
||||||
<ul>
|
<tr>
|
||||||
<li>项目名称 : ${PROJECT_NAME}</li>
|
<td>
|
||||||
<li>构建编号 : 第${BUILD_NUMBER}次构建</li>
|
<ul>
|
||||||
<li>触发原因: ${CAUSE}</li>
|
<li>项目名称 : ${PROJECT_NAME}</li>
|
||||||
<li>构建日志: <a href="${BUILD_URL}console">${BUILD_URL}console</a></li>
|
<li>构建编号 : 第${BUILD_NUMBER}次构建</li>
|
||||||
<li>构建 Url : <a href="${BUILD_URL}">${BUILD_URL}</a></li>
|
<li>触发原因: ${CAUSE}</li>
|
||||||
<li>工作目录 : <a href="${PROJECT_URL}ws">${PROJECT_URL}</a></li>
|
<li>构建日志: <a href="${BUILD_URL}console">${BUILD_URL}console</a></li>
|
||||||
<li>项目 Url : <a href="${PROJECT_URL}">${PROJECT_URL}</a></li>
|
<li>构建 Url : <a href="${BUILD_URL}">${BUILD_URL}</a></li>
|
||||||
</ul>
|
<li>工作目录 : <a href="${PROJECT_URL}ws">${PROJECT_URL}</a></li>
|
||||||
</td>
|
<li>项目 Url : <a href="${PROJECT_URL}">${PROJECT_URL}</a></li>
|
||||||
</tr>
|
</ul>
|
||||||
<tr>
|
</td>
|
||||||
<td><b><font color="#0B610B">Changes Since Last
|
</tr>
|
||||||
Successful Build:</font></b>
|
<tr>
|
||||||
<hr size="2" width="100%" align="center" /></td>
|
<td>
|
||||||
</tr>
|
<b><font color="#0B610B">Changes Since Last Successful Build:</font></b>
|
||||||
<tr>
|
<hr size="2" width="100%" align="center" />
|
||||||
<td>
|
</td>
|
||||||
<ul>
|
</tr>
|
||||||
<li>历史变更记录 : <a href="${PROJECT_URL}changes">${PROJECT_URL}changes</a></li>
|
<tr>
|
||||||
</ul> ${CHANGES_SINCE_LAST_SUCCESS,reverse=true, format="Changes for Build #%n:<br />%c<br />",showPaths=true,changesFormat="<pre>[%a]<br />%m</pre>",pathFormat=" %p"}
|
<td>
|
||||||
</td>
|
<ul>
|
||||||
</tr>
|
<li>历史变更记录 : <a href="${PROJECT_URL}changes">${PROJECT_URL}changes</a></li>
|
||||||
<tr>
|
</ul>
|
||||||
<td><b>Failed Test Results</b>
|
${CHANGES_SINCE_LAST_SUCCESS,reverse=true, format="Changes for Build #%n:<br />%c<br />",showPaths=true,changesFormat="
|
||||||
<hr size="2" width="100%" align="center" /></td>
|
<pre>[%a]<br />%m</pre>
|
||||||
</tr>
|
",pathFormat=" %p"}
|
||||||
<tr>
|
</td>
|
||||||
<td><pre
|
</tr>
|
||||||
style="font-size: 11pt; font-family: Tahoma, Arial, Helvetica, sans-serif">$FAILED_TESTS</pre>
|
<tr>
|
||||||
<br /></td>
|
<td>
|
||||||
</tr>
|
<b>Failed Test Results</b>
|
||||||
<tr>
|
<hr size="2" width="100%" align="center" />
|
||||||
<td><b><font color="#0B610B">构建日志 (最后 100行):</font></b>
|
</td>
|
||||||
<hr size="2" width="100%" align="center" /></td>
|
</tr>
|
||||||
</tr>
|
<tr>
|
||||||
<tr>
|
<td>
|
||||||
<td>Test Logs (if test has ran):
|
<pre style="font-size: 11pt; font-family: Tahoma, Arial, Helvetica, sans-serif">$FAILED_TESTS</pre>
|
||||||
<a href="${PROJECT_URL}ws/TestResult/archive_logs/Log-Build-${BUILD_NUMBER}.zip">${PROJECT_URL}/ws/TestResult/archive_logs/Log-Build-${BUILD_NUMBER}.zip</a>
|
<br />
|
||||||
<br />
|
</td>
|
||||||
<br />
|
</tr>
|
||||||
</td>
|
<tr>
|
||||||
</tr>
|
<td>
|
||||||
<tr>
|
<b><font color="#0B610B">构建日志 (最后 100行):</font></b>
|
||||||
<td><textarea cols="80" rows="30" readonly="readonly"
|
<hr size="2" width="100%" align="center" />
|
||||||
style="font-family: Courier New">${BUILD_LOG}</textarea>
|
</td>
|
||||||
</td>
|
</tr>
|
||||||
</tr>
|
<tr>
|
||||||
</table>
|
<td>
|
||||||
</body>
|
Test Logs (if test has ran):
|
||||||
|
<a href="${PROJECT_URL}ws/TestResult/archive_logs/Log-Build-${BUILD_NUMBER}.zip"
|
||||||
|
>${PROJECT_URL}/ws/TestResult/archive_logs/Log-Build-${BUILD_NUMBER}.zip</a
|
||||||
|
>
|
||||||
|
<br />
|
||||||
|
<br />
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td><textarea cols="80" rows="30" readonly="readonly" style="font-family: Courier New">${BUILD_LOG}</textarea></td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
</body>
|
||||||
</html>
|
</html>
|
||||||
@@ -1,77 +1,89 @@
|
|||||||
<!DOCTYPE html>
|
<!DOCTYPE html>
|
||||||
<html>
|
<html>
|
||||||
<head>
|
<head>
|
||||||
<meta charset="UTF-8">
|
<meta charset="UTF-8" />
|
||||||
<title>${ENV, var="JOB_NAME"}-第${BUILD_NUMBER}次构建日志</title>
|
<title>${ENV, var="JOB_NAME"}-第${BUILD_NUMBER}次构建日志</title>
|
||||||
</head>
|
</head>
|
||||||
|
|
||||||
<body leftmargin="8" marginwidth="0" topmargin="8" marginheight="4"
|
<body leftmargin="8" marginwidth="0" topmargin="8" marginheight="4" offset="0">
|
||||||
offset="0">
|
<table width="95%" cellpadding="0" cellspacing="0" style="font-size: 11pt; font-family: Tahoma, Arial, Helvetica, sans-serif">
|
||||||
<table width="95%" cellpadding="0" cellspacing="0"
|
<tr>
|
||||||
style="font-size: 11pt; font-family: Tahoma, Arial, Helvetica, sans-serif">
|
<td>(本邮件是程序自动下发的,请勿回复!)</td>
|
||||||
<tr>
|
</tr>
|
||||||
<td>(本邮件是程序自动下发的,请勿回复!)</td>
|
<tr>
|
||||||
</tr>
|
<td>
|
||||||
<tr>
|
<h2>
|
||||||
<td><h2>
|
<font color="#228B22">构建结果 - ${BUILD_STATUS}</font>
|
||||||
<font color="#228B22">构建结果 - ${BUILD_STATUS}</font>
|
</h2>
|
||||||
</h2></td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td><br />
|
<td>
|
||||||
<b><font color="#0B610B">构建信息</font></b>
|
<br />
|
||||||
<hr size="2" width="100%" align="center" /></td>
|
<b><font color="#0B610B">构建信息</font></b>
|
||||||
</tr>
|
<hr size="2" width="100%" align="center" />
|
||||||
<tr>
|
</td>
|
||||||
<td>
|
</tr>
|
||||||
<ul>
|
<tr>
|
||||||
<li>项目名称 : ${PROJECT_NAME}</li>
|
<td>
|
||||||
<li>构建编号 : 第${BUILD_NUMBER}次构建</li>
|
<ul>
|
||||||
<li>触发原因: ${CAUSE}</li>
|
<li>项目名称 : ${PROJECT_NAME}</li>
|
||||||
<li>构建日志: <a href="${BUILD_URL}console">${BUILD_URL}console</a></li>
|
<li>构建编号 : 第${BUILD_NUMBER}次构建</li>
|
||||||
<li>构建 Url : <a href="${BUILD_URL}">${BUILD_URL}</a></li>
|
<li>触发原因: ${CAUSE}</li>
|
||||||
<li>工作目录 : <a href="${PROJECT_URL}ws">${PROJECT_URL}</a></li>
|
<li>构建日志: <a href="${BUILD_URL}console">${BUILD_URL}console</a></li>
|
||||||
<li>项目 Url : <a href="${PROJECT_URL}">${PROJECT_URL}</a></li>
|
<li>构建 Url : <a href="${BUILD_URL}">${BUILD_URL}</a></li>
|
||||||
</ul>
|
<li>工作目录 : <a href="${PROJECT_URL}ws">${PROJECT_URL}</a></li>
|
||||||
</td>
|
<li>项目 Url : <a href="${PROJECT_URL}">${PROJECT_URL}</a></li>
|
||||||
</tr>
|
</ul>
|
||||||
<tr>
|
</td>
|
||||||
<td><b><font color="#0B610B">Changes Since Last
|
</tr>
|
||||||
Successful Build:</font></b>
|
<tr>
|
||||||
<hr size="2" width="100%" align="center" /></td>
|
<td>
|
||||||
</tr>
|
<b><font color="#0B610B">Changes Since Last Successful Build:</font></b>
|
||||||
<tr>
|
<hr size="2" width="100%" align="center" />
|
||||||
<td>
|
</td>
|
||||||
<ul>
|
</tr>
|
||||||
<li>历史变更记录 : <a href="${PROJECT_URL}changes">${PROJECT_URL}changes</a></li>
|
<tr>
|
||||||
</ul> ${CHANGES_SINCE_LAST_SUCCESS,reverse=true, format="Changes for Build #%n:<br />%c<br />",showPaths=true,changesFormat="<pre>[%a]<br />%m</pre>",pathFormat=" %p"}
|
<td>
|
||||||
</td>
|
<ul>
|
||||||
</tr>
|
<li>历史变更记录 : <a href="${PROJECT_URL}changes">${PROJECT_URL}changes</a></li>
|
||||||
<tr>
|
</ul>
|
||||||
<td><b>Failed Test Results</b>
|
${CHANGES_SINCE_LAST_SUCCESS,reverse=true, format="Changes for Build #%n:<br />%c<br />",showPaths=true,changesFormat="
|
||||||
<hr size="2" width="100%" align="center" /></td>
|
<pre>[%a]<br />%m</pre>
|
||||||
</tr>
|
",pathFormat=" %p"}
|
||||||
<tr>
|
</td>
|
||||||
<td><pre
|
</tr>
|
||||||
style="font-size: 11pt; font-family: Tahoma, Arial, Helvetica, sans-serif">$FAILED_TESTS</pre>
|
<tr>
|
||||||
<br /></td>
|
<td>
|
||||||
</tr>
|
<b>Failed Test Results</b>
|
||||||
<tr>
|
<hr size="2" width="100%" align="center" />
|
||||||
<td><b><font color="#0B610B">构建日志 (最后 100行):</font></b>
|
</td>
|
||||||
<hr size="2" width="100%" align="center" /></td>
|
</tr>
|
||||||
</tr>
|
<tr>
|
||||||
<tr>
|
<td>
|
||||||
<td>Test Logs (if test has ran):
|
<pre style="font-size: 11pt; font-family: Tahoma, Arial, Helvetica, sans-serif">$FAILED_TESTS</pre>
|
||||||
<a href="${PROJECT_URL}ws/TestResult/archive_logs/Log-Build-${BUILD_NUMBER}.zip">${PROJECT_URL}/ws/TestResult/archive_logs/Log-Build-${BUILD_NUMBER}.zip</a>
|
<br />
|
||||||
<br />
|
</td>
|
||||||
<br />
|
</tr>
|
||||||
</td>
|
<tr>
|
||||||
</tr>
|
<td>
|
||||||
<tr>
|
<b><font color="#0B610B">构建日志 (最后 100行):</font></b>
|
||||||
<td><textarea cols="80" rows="30" readonly="readonly"
|
<hr size="2" width="100%" align="center" />
|
||||||
style="font-family: Courier New">${BUILD_LOG}</textarea>
|
</td>
|
||||||
</td>
|
</tr>
|
||||||
</tr>
|
<tr>
|
||||||
</table>
|
<td>
|
||||||
</body>
|
Test Logs (if test has ran):
|
||||||
|
<a href="${PROJECT_URL}ws/TestResult/archive_logs/Log-Build-${BUILD_NUMBER}.zip"
|
||||||
|
>${PROJECT_URL}/ws/TestResult/archive_logs/Log-Build-${BUILD_NUMBER}.zip</a
|
||||||
|
>
|
||||||
|
<br />
|
||||||
|
<br />
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td><textarea cols="80" rows="30" readonly="readonly" style="font-family: Courier New">${BUILD_LOG}</textarea></td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
</body>
|
||||||
</html>
|
</html>
|
||||||
@@ -154,7 +154,18 @@ watch(templateFiles, (files) => {
|
|||||||
}, { deep: true })
|
}, { deep: true })
|
||||||
|
|
||||||
const rules: FormRules = {
|
const rules: FormRules = {
|
||||||
acceptDate: [{ required: true, message: '请选择验收日期', trigger: 'change' }],
|
templateFileIds: [
|
||||||
|
{
|
||||||
|
validator: (_rule: any, value: any, callback: (e?: Error) => void) => {
|
||||||
|
if (!value || (Array.isArray(value) && value.length === 0) || (typeof value === 'string' && !value.trim())) {
|
||||||
|
callback(new Error('请上传履约验收文件'))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
callback()
|
||||||
|
},
|
||||||
|
trigger: 'change'
|
||||||
|
},
|
||||||
|
],
|
||||||
}
|
}
|
||||||
|
|
||||||
const validate = () => formRef.value?.validate()
|
const validate = () => formRef.value?.validate()
|
||||||
|
|||||||
@@ -58,8 +58,30 @@
|
|||||||
</el-form-item>
|
</el-form-item>
|
||||||
</el-col>
|
</el-col>
|
||||||
<el-col :span="8" class="mb20">
|
<el-col :span="8" class="mb20">
|
||||||
<el-form-item label="供应商联系人及电话" prop="supplierContact">
|
<el-form-item label="资产管理员" prop="assetAdminId">
|
||||||
<el-input v-model="form.supplierContact" placeholder="请输入" clearable />
|
<el-select
|
||||||
|
v-model="form.assetAdminId"
|
||||||
|
placeholder="请输入姓名或工号搜索"
|
||||||
|
filterable
|
||||||
|
remote
|
||||||
|
clearable
|
||||||
|
reserve-keyword
|
||||||
|
:remote-method="searchAssetAdmin"
|
||||||
|
:loading="assetAdminLoading"
|
||||||
|
style="width: 100%"
|
||||||
|
@change="onAssetAdminChange"
|
||||||
|
>
|
||||||
|
<el-option
|
||||||
|
v-for="item in assetAdminOptions"
|
||||||
|
:key="item.teacherNo"
|
||||||
|
:label="(item.commonDeptName ? item.commonDeptName + ' - ' : '') + (item.realName || item.name) + ' (' + item.teacherNo + ')'"
|
||||||
|
:value="item.teacherNo"
|
||||||
|
>
|
||||||
|
<span>{{ item.commonDeptName ? item.commonDeptName + ' - ' : '' }}{{ item.realName || item.name }}</span>
|
||||||
|
<span style="color: #999; font-size: 12px; margin-left: 8px;">{{ item.teacherNo }}</span>
|
||||||
|
</el-option>
|
||||||
|
</el-select>
|
||||||
|
<div class="field-note">如入固定资产,必填</div>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
</el-col>
|
</el-col>
|
||||||
<el-col :span="8" class="mb20">
|
<el-col :span="8" class="mb20">
|
||||||
@@ -167,7 +189,6 @@ const form = reactive({
|
|||||||
projectName: '',
|
projectName: '',
|
||||||
deptName: '',
|
deptName: '',
|
||||||
supplierName: '',
|
supplierName: '',
|
||||||
supplierContact: '',
|
|
||||||
purchaserId: '',
|
purchaserId: '',
|
||||||
purchaserName: '',
|
purchaserName: '',
|
||||||
assetAdminId: '',
|
assetAdminId: '',
|
||||||
@@ -336,4 +357,9 @@ defineExpose({ validate, form })
|
|||||||
.mb20 {
|
.mb20 {
|
||||||
margin-bottom: 20px;
|
margin-bottom: 20px;
|
||||||
}
|
}
|
||||||
|
.field-note {
|
||||||
|
font-size: 12px;
|
||||||
|
color: #999;
|
||||||
|
margin-top: 4px;
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
@@ -192,7 +192,6 @@ const loadData = async () => {
|
|||||||
isInstallment: config.common.isInstallment || '0',
|
isInstallment: config.common.isInstallment || '0',
|
||||||
totalPhases: config.common.totalPhases || 1,
|
totalPhases: config.common.totalPhases || 1,
|
||||||
supplierName: config.common.supplierName || '',
|
supplierName: config.common.supplierName || '',
|
||||||
supplierContact: config.common.supplierContact || '',
|
|
||||||
transactionAmount: config.common.transactionAmount || null,
|
transactionAmount: config.common.transactionAmount || null,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@@ -278,7 +277,6 @@ const saveCommonConfig = async () => {
|
|||||||
isInstallment: form.isInstallment ?? '0',
|
isInstallment: form.isInstallment ?? '0',
|
||||||
totalPhases: isInstallment ? (Number(form.totalPhases) || 1) : 1,
|
totalPhases: isInstallment ? (Number(form.totalPhases) || 1) : 1,
|
||||||
supplierName: String(form.supplierName ?? ''),
|
supplierName: String(form.supplierName ?? ''),
|
||||||
supplierContact: String(form.supplierContact ?? ''),
|
|
||||||
purchaserId: String(form.purchaserId ?? ''),
|
purchaserId: String(form.purchaserId ?? ''),
|
||||||
purchaserName: String(form.purchaserName ?? ''),
|
purchaserName: String(form.purchaserName ?? ''),
|
||||||
assetAdminId: String(form.assetAdminId ?? ''),
|
assetAdminId: String(form.assetAdminId ?? ''),
|
||||||
@@ -307,10 +305,7 @@ const saveCurrentBatch = async () => {
|
|||||||
const formData = batchFormRef?.getFormData?.() || batchFormRef?.form
|
const formData = batchFormRef?.getFormData?.() || batchFormRef?.form
|
||||||
if (!formData) return
|
if (!formData) return
|
||||||
|
|
||||||
if (!formData.acceptDate) {
|
// acceptDate is now optional - removed the validation check
|
||||||
useMessage().error('请选择验收日期')
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// templateFileIds: 提取ID数组
|
// templateFileIds: 提取ID数组
|
||||||
let fileIds: string[] = []
|
let fileIds: string[] = []
|
||||||
@@ -357,7 +352,6 @@ const DEFAULT_COMMON_FORM = {
|
|||||||
isInstallment: '0',
|
isInstallment: '0',
|
||||||
totalPhases: 1,
|
totalPhases: 1,
|
||||||
supplierName: '',
|
supplierName: '',
|
||||||
supplierContact: '',
|
|
||||||
purchaserId: '',
|
purchaserId: '',
|
||||||
purchaserName: '',
|
purchaserName: '',
|
||||||
assetAdminId: '',
|
assetAdminId: '',
|
||||||
|
|||||||
@@ -205,7 +205,7 @@
|
|||||||
<upload-file
|
<upload-file
|
||||||
v-model="dataForm.businessNegotiationTable"
|
v-model="dataForm.businessNegotiationTable"
|
||||||
:limit="1"
|
:limit="1"
|
||||||
:file-type="['doc', 'docx', 'pdf']"
|
:file-type="['doc', 'docx', 'pdf', 'jpg', 'jpeg', 'png', 'gif', 'bmp', 'webp']"
|
||||||
:data="{ fileType: FILE_TYPE_MAP.businessNegotiationTable }"
|
:data="{ fileType: FILE_TYPE_MAP.businessNegotiationTable }"
|
||||||
upload-file-url="/purchase/purchasingfiles/upload"
|
upload-file-url="/purchase/purchasingfiles/upload"
|
||||||
:disabled="flowFieldDisabled('businessNegotiationTable')"
|
:disabled="flowFieldDisabled('businessNegotiationTable')"
|
||||||
@@ -226,7 +226,7 @@
|
|||||||
<upload-file
|
<upload-file
|
||||||
v-model="dataForm.marketPurchaseMinutes"
|
v-model="dataForm.marketPurchaseMinutes"
|
||||||
:limit="1"
|
:limit="1"
|
||||||
:file-type="['doc', 'docx', 'pdf']"
|
:file-type="['doc', 'docx', 'pdf', 'jpg', 'jpeg', 'png', 'gif', 'bmp', 'webp']"
|
||||||
:data="{ fileType: FILE_TYPE_MAP.marketPurchaseMinutes }"
|
:data="{ fileType: FILE_TYPE_MAP.marketPurchaseMinutes }"
|
||||||
upload-file-url="/purchase/purchasingfiles/upload"
|
upload-file-url="/purchase/purchasingfiles/upload"
|
||||||
:disabled="flowFieldDisabled('marketPurchaseMinutes')"
|
:disabled="flowFieldDisabled('marketPurchaseMinutes')"
|
||||||
@@ -247,7 +247,7 @@
|
|||||||
<upload-file
|
<upload-file
|
||||||
v-model="dataForm.onlineMallMaterials"
|
v-model="dataForm.onlineMallMaterials"
|
||||||
:limit="1"
|
:limit="1"
|
||||||
:file-type="['doc', 'docx', 'pdf']"
|
:file-type="['doc', 'docx', 'pdf', 'jpg', 'jpeg', 'png', 'gif', 'bmp', 'webp']"
|
||||||
:data="{ fileType: FILE_TYPE_MAP.onlineMallMaterials }"
|
:data="{ fileType: FILE_TYPE_MAP.onlineMallMaterials }"
|
||||||
upload-file-url="/purchase/purchasingfiles/upload"
|
upload-file-url="/purchase/purchasingfiles/upload"
|
||||||
:disabled="flowFieldDisabled('onlineMallMaterials')"
|
:disabled="flowFieldDisabled('onlineMallMaterials')"
|
||||||
@@ -259,7 +259,7 @@
|
|||||||
<upload-file
|
<upload-file
|
||||||
v-model="dataForm.inquiryTemplate"
|
v-model="dataForm.inquiryTemplate"
|
||||||
:limit="1"
|
:limit="1"
|
||||||
:file-type="['doc', 'docx', 'pdf']"
|
:file-type="['doc', 'docx', 'pdf', 'jpg', 'jpeg', 'png', 'gif', 'bmp', 'webp']"
|
||||||
:data="{ fileType: FILE_TYPE_MAP.inquiryTemplate }"
|
:data="{ fileType: FILE_TYPE_MAP.inquiryTemplate }"
|
||||||
upload-file-url="/purchase/purchasingfiles/upload"
|
upload-file-url="/purchase/purchasingfiles/upload"
|
||||||
:disabled="flowFieldDisabled('inquiryTemplate')"
|
:disabled="flowFieldDisabled('inquiryTemplate')"
|
||||||
@@ -278,13 +278,13 @@
|
|||||||
<el-col
|
<el-col
|
||||||
:span="8"
|
:span="8"
|
||||||
class="mb12"
|
class="mb12"
|
||||||
v-if="isDeptPurchase && dataForm.budget != null && dataForm.budget >= BUDGET_DEPT_SELF_MEETING_MINUTES"
|
v-if="dataForm.budget != null && dataForm.budget >= BUDGET_DEPT_SELF_MEETING_MINUTES"
|
||||||
>
|
>
|
||||||
<el-form-item label="部门自行采购会议纪要" prop="deptSelfMeetingMinutes" required>
|
<el-form-item label="部门自行采购会议纪要" prop="deptSelfMeetingMinutes" required>
|
||||||
<upload-file
|
<upload-file
|
||||||
v-model="dataForm.deptSelfMeetingMinutes"
|
v-model="dataForm.deptSelfMeetingMinutes"
|
||||||
:limit="1"
|
:limit="1"
|
||||||
:file-type="['doc', 'docx', 'pdf']"
|
:file-type="['doc', 'docx', 'pdf', 'jpg', 'jpeg', 'png', 'gif', 'bmp', 'webp']"
|
||||||
:data="{ fileType: FILE_TYPE_MAP.deptSelfMeetingMinutes }"
|
:data="{ fileType: FILE_TYPE_MAP.deptSelfMeetingMinutes }"
|
||||||
upload-file-url="/purchase/purchasingfiles/upload"
|
upload-file-url="/purchase/purchasingfiles/upload"
|
||||||
:disabled="flowFieldDisabled('deptSelfMeetingMinutes')"
|
:disabled="flowFieldDisabled('deptSelfMeetingMinutes')"
|
||||||
@@ -320,7 +320,7 @@
|
|||||||
<upload-file
|
<upload-file
|
||||||
v-model="dataForm.serviceDirectSelect"
|
v-model="dataForm.serviceDirectSelect"
|
||||||
:limit="1"
|
:limit="1"
|
||||||
:file-type="['doc', 'docx', 'pdf']"
|
:file-type="['doc', 'docx', 'pdf', 'jpg', 'jpeg', 'png', 'gif', 'bmp', 'webp']"
|
||||||
:data="{ fileType: FILE_TYPE_MAP.serviceDirectSelect }"
|
:data="{ fileType: FILE_TYPE_MAP.serviceDirectSelect }"
|
||||||
upload-file-url="/purchase/purchasingfiles/upload"
|
upload-file-url="/purchase/purchasingfiles/upload"
|
||||||
:disabled="flowFieldDisabled('serviceDirectSelect')"
|
:disabled="flowFieldDisabled('serviceDirectSelect')"
|
||||||
@@ -351,7 +351,7 @@
|
|||||||
<upload-file
|
<upload-file
|
||||||
v-model="dataForm.serviceInviteSelect"
|
v-model="dataForm.serviceInviteSelect"
|
||||||
:limit="1"
|
:limit="1"
|
||||||
:file-type="['doc', 'docx', 'pdf']"
|
:file-type="['doc', 'docx', 'pdf', 'jpg', 'jpeg', 'png', 'gif', 'bmp', 'webp']"
|
||||||
:data="{ fileType: FILE_TYPE_MAP.serviceInviteSelect }"
|
:data="{ fileType: FILE_TYPE_MAP.serviceInviteSelect }"
|
||||||
upload-file-url="/purchase/purchasingfiles/upload"
|
upload-file-url="/purchase/purchasingfiles/upload"
|
||||||
:disabled="flowFieldDisabled('serviceInviteSelect')"
|
:disabled="flowFieldDisabled('serviceInviteSelect')"
|
||||||
@@ -376,7 +376,7 @@
|
|||||||
<upload-file
|
<upload-file
|
||||||
v-model="dataForm.purchaseRequirementTemplate"
|
v-model="dataForm.purchaseRequirementTemplate"
|
||||||
:limit="1"
|
:limit="1"
|
||||||
:file-type="['doc', 'docx', 'pdf']"
|
:file-type="['doc', 'docx']"
|
||||||
:data="{ fileType: FILE_TYPE_MAP.purchaseRequirementTemplate }"
|
:data="{ fileType: FILE_TYPE_MAP.purchaseRequirementTemplate }"
|
||||||
upload-file-url="/purchase/purchasingfiles/upload"
|
upload-file-url="/purchase/purchasingfiles/upload"
|
||||||
:disabled="flowFieldDisabled('purchaseRequirementTemplate')"
|
:disabled="flowFieldDisabled('purchaseRequirementTemplate')"
|
||||||
@@ -405,7 +405,7 @@
|
|||||||
<upload-file
|
<upload-file
|
||||||
v-model="dataForm.serviceInviteSelect"
|
v-model="dataForm.serviceInviteSelect"
|
||||||
:limit="1"
|
:limit="1"
|
||||||
:file-type="['doc', 'docx', 'pdf']"
|
:file-type="['doc', 'docx', 'pdf', 'jpg', 'jpeg', 'png', 'gif', 'bmp', 'webp']"
|
||||||
:data="{ fileType: FILE_TYPE_MAP.serviceInviteSelect }"
|
:data="{ fileType: FILE_TYPE_MAP.serviceInviteSelect }"
|
||||||
upload-file-url="/purchase/purchasingfiles/upload"
|
upload-file-url="/purchase/purchasingfiles/upload"
|
||||||
:disabled="flowFieldDisabled('serviceInviteSelect')"
|
:disabled="flowFieldDisabled('serviceInviteSelect')"
|
||||||
@@ -426,7 +426,7 @@
|
|||||||
<upload-file
|
<upload-file
|
||||||
v-model="dataForm.servicePublicSelectAuto"
|
v-model="dataForm.servicePublicSelectAuto"
|
||||||
:limit="1"
|
:limit="1"
|
||||||
:file-type="['doc', 'docx', 'pdf']"
|
:file-type="['doc', 'docx', 'pdf', 'jpg', 'jpeg', 'png', 'gif', 'bmp', 'webp']"
|
||||||
:data="{ fileType: FILE_TYPE_MAP.servicePublicSelectAuto }"
|
:data="{ fileType: FILE_TYPE_MAP.servicePublicSelectAuto }"
|
||||||
upload-file-url="/purchase/purchasingfiles/upload"
|
upload-file-url="/purchase/purchasingfiles/upload"
|
||||||
:disabled="flowFieldDisabled('servicePublicSelectAuto')"
|
:disabled="flowFieldDisabled('servicePublicSelectAuto')"
|
||||||
@@ -556,7 +556,7 @@
|
|||||||
<upload-file
|
<upload-file
|
||||||
v-model="dataForm.feasibilityReport"
|
v-model="dataForm.feasibilityReport"
|
||||||
:limit="1"
|
:limit="1"
|
||||||
:file-type="['doc', 'docx', 'pdf']"
|
:file-type="['doc', 'docx', 'pdf', 'jpg', 'jpeg', 'png', 'gif', 'bmp', 'webp']"
|
||||||
:data="{ fileType: FILE_TYPE_MAP.feasibilityReport }"
|
:data="{ fileType: FILE_TYPE_MAP.feasibilityReport }"
|
||||||
upload-file-url="/purchase/purchasingfiles/upload"
|
upload-file-url="/purchase/purchasingfiles/upload"
|
||||||
:disabled="flowFieldDisabled('feasibilityReport')"
|
:disabled="flowFieldDisabled('feasibilityReport')"
|
||||||
@@ -577,41 +577,28 @@
|
|||||||
class="mb12"
|
class="mb12"
|
||||||
v-if="
|
v-if="
|
||||||
dataForm.budget &&
|
dataForm.budget &&
|
||||||
dataForm.budget >= BUDGET_FEASIBILITY_THRESHOLD &&
|
(dataForm.budget >= BUDGET_FEASIBILITY_THRESHOLD || !isSpecialType('0'))
|
||||||
!isUrgentSpecial &&
|
|
||||||
!isSpecialType('2') &&
|
|
||||||
!isSpecialType('3')
|
|
||||||
"
|
"
|
||||||
>
|
>
|
||||||
<el-form-item label="校党委会议纪要" prop="meetingMinutes" required>
|
<el-form-item label="校党委会议纪要" prop="meetingMinutes" required>
|
||||||
<upload-file
|
<upload-file
|
||||||
v-model="dataForm.meetingMinutes"
|
v-model="dataForm.meetingMinutes"
|
||||||
:limit="1"
|
:limit="1"
|
||||||
:file-type="['doc', 'docx', 'pdf']"
|
:file-type="['doc', 'docx', 'pdf', 'jpg', 'jpeg', 'png', 'gif', 'bmp', 'webp']"
|
||||||
:data="{ fileType: FILE_TYPE_MAP.meetingMinutes }"
|
:data="{ fileType: FILE_TYPE_MAP.meetingMinutes }"
|
||||||
upload-file-url="/purchase/purchasingfiles/upload"
|
upload-file-url="/purchase/purchasingfiles/upload"
|
||||||
:disabled="flowFieldDisabled('meetingMinutes')"
|
:disabled="flowFieldDisabled('meetingMinutes')"
|
||||||
/>
|
/>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
</el-col>
|
</el-col>
|
||||||
<el-col :span="8" class="mb12" v-if="isUrgentSpecial">
|
|
||||||
<el-form-item label="校党委会议纪要(紧急)" prop="meetingMinutesUrgent" required>
|
|
||||||
<upload-file
|
|
||||||
v-model="dataForm.meetingMinutesUrgent"
|
|
||||||
:limit="1"
|
|
||||||
:file-type="['doc', 'docx', 'pdf']"
|
|
||||||
:data="{ fileType: FILE_TYPE_MAP.meetingMinutesUrgent }"
|
|
||||||
upload-file-url="/purchase/purchasingfiles/upload"
|
|
||||||
:disabled="flowFieldDisabled('meetingMinutesUrgent')"
|
|
||||||
/>
|
|
||||||
</el-form-item>
|
|
||||||
</el-col>
|
|
||||||
<el-col :span="8" class="mb12" v-if="isSpecialType('2')">
|
<el-col :span="8" class="mb12" v-if="isSpecialType('2')">
|
||||||
<el-form-item label="单一来源论专家证附件" prop="singleSourceProof" required>
|
<el-form-item label="单一来源论专家证附件" prop="singleSourceProof" required>
|
||||||
<upload-file
|
<upload-file
|
||||||
v-model="dataForm.singleSourceProof"
|
v-model="dataForm.singleSourceProof"
|
||||||
:limit="1"
|
:limit="1"
|
||||||
:file-type="['doc', 'docx', 'pdf']"
|
:file-type="['doc', 'docx', 'pdf', 'jpg', 'jpeg', 'png', 'gif', 'bmp', 'webp']"
|
||||||
:data="{ fileType: FILE_TYPE_MAP.singleSourceProof }"
|
:data="{ fileType: FILE_TYPE_MAP.singleSourceProof }"
|
||||||
upload-file-url="/purchase/purchasingfiles/upload"
|
upload-file-url="/purchase/purchasingfiles/upload"
|
||||||
:disabled="flowFieldDisabled('singleSourceProof')"
|
:disabled="flowFieldDisabled('singleSourceProof')"
|
||||||
@@ -632,7 +619,7 @@
|
|||||||
<upload-file
|
<upload-file
|
||||||
v-model="dataForm.meetingMinutesSingle"
|
v-model="dataForm.meetingMinutesSingle"
|
||||||
:limit="1"
|
:limit="1"
|
||||||
:file-type="['doc', 'docx', 'pdf']"
|
:file-type="['doc', 'docx', 'pdf', 'jpg', 'jpeg', 'png', 'gif', 'bmp', 'webp']"
|
||||||
:data="{ fileType: FILE_TYPE_MAP.meetingMinutesSingle }"
|
:data="{ fileType: FILE_TYPE_MAP.meetingMinutesSingle }"
|
||||||
upload-file-url="/purchase/purchasingfiles/upload"
|
upload-file-url="/purchase/purchasingfiles/upload"
|
||||||
:disabled="flowFieldDisabled('meetingMinutesSingle')"
|
:disabled="flowFieldDisabled('meetingMinutesSingle')"
|
||||||
@@ -644,7 +631,7 @@
|
|||||||
<upload-file
|
<upload-file
|
||||||
v-model="dataForm.importApplication"
|
v-model="dataForm.importApplication"
|
||||||
:limit="1"
|
:limit="1"
|
||||||
:file-type="['doc', 'docx', 'pdf']"
|
:file-type="['doc', 'docx', 'pdf', 'jpg', 'jpeg', 'png', 'gif', 'bmp', 'webp']"
|
||||||
:data="{ fileType: FILE_TYPE_MAP.importApplication }"
|
:data="{ fileType: FILE_TYPE_MAP.importApplication }"
|
||||||
upload-file-url="/purchase/purchasingfiles/upload"
|
upload-file-url="/purchase/purchasingfiles/upload"
|
||||||
:disabled="flowFieldDisabled('importApplication')"
|
:disabled="flowFieldDisabled('importApplication')"
|
||||||
@@ -665,7 +652,7 @@
|
|||||||
<upload-file
|
<upload-file
|
||||||
v-model="dataForm.meetingMinutesImport"
|
v-model="dataForm.meetingMinutesImport"
|
||||||
:limit="1"
|
:limit="1"
|
||||||
:file-type="['doc', 'docx', 'pdf']"
|
:file-type="['doc', 'docx', 'pdf', 'jpg', 'jpeg', 'png', 'gif', 'bmp', 'webp']"
|
||||||
:data="{ fileType: FILE_TYPE_MAP.meetingMinutesImport }"
|
:data="{ fileType: FILE_TYPE_MAP.meetingMinutesImport }"
|
||||||
upload-file-url="/purchase/purchasingfiles/upload"
|
upload-file-url="/purchase/purchasingfiles/upload"
|
||||||
:disabled="flowFieldDisabled('meetingMinutesImport')"
|
:disabled="flowFieldDisabled('meetingMinutesImport')"
|
||||||
@@ -693,7 +680,7 @@
|
|||||||
<upload-file
|
<upload-file
|
||||||
v-model="dataForm.serviceInviteSelectSchool"
|
v-model="dataForm.serviceInviteSelectSchool"
|
||||||
:limit="1"
|
:limit="1"
|
||||||
:file-type="['doc', 'docx', 'pdf']"
|
:file-type="['doc', 'docx', 'pdf', 'jpg', 'jpeg', 'png', 'gif', 'bmp', 'webp']"
|
||||||
:data="{ fileType: FILE_TYPE_MAP.serviceInviteSelectSchool }"
|
:data="{ fileType: FILE_TYPE_MAP.serviceInviteSelectSchool }"
|
||||||
upload-file-url="/purchase/purchasingfiles/upload"
|
upload-file-url="/purchase/purchasingfiles/upload"
|
||||||
:disabled="flowFieldDisabled('serviceInviteSelectSchool')"
|
:disabled="flowFieldDisabled('serviceInviteSelectSchool')"
|
||||||
@@ -712,7 +699,7 @@
|
|||||||
<upload-file
|
<upload-file
|
||||||
v-model="dataForm.servicePublicSelectSchoolAuto"
|
v-model="dataForm.servicePublicSelectSchoolAuto"
|
||||||
:limit="1"
|
:limit="1"
|
||||||
:file-type="['doc', 'docx', 'pdf']"
|
:file-type="['doc', 'docx', 'pdf', 'jpg', 'jpeg', 'png', 'gif', 'bmp', 'webp']"
|
||||||
:data="{ fileType: FILE_TYPE_MAP.servicePublicSelectSchoolAuto }"
|
:data="{ fileType: FILE_TYPE_MAP.servicePublicSelectSchoolAuto }"
|
||||||
upload-file-url="/purchase/purchasingfiles/upload"
|
upload-file-url="/purchase/purchasingfiles/upload"
|
||||||
:disabled="flowFieldDisabled('servicePublicSelectSchoolAuto')"
|
:disabled="flowFieldDisabled('servicePublicSelectSchoolAuto')"
|
||||||
@@ -732,7 +719,7 @@
|
|||||||
<upload-file
|
<upload-file
|
||||||
v-model="dataForm.servicePublicSelectSchool"
|
v-model="dataForm.servicePublicSelectSchool"
|
||||||
:limit="1"
|
:limit="1"
|
||||||
:file-type="['doc', 'docx', 'pdf']"
|
:file-type="['doc', 'docx', 'pdf', 'jpg', 'jpeg', 'png', 'gif', 'bmp', 'webp']"
|
||||||
:data="{ fileType: FILE_TYPE_MAP.servicePublicSelectSchool }"
|
:data="{ fileType: FILE_TYPE_MAP.servicePublicSelectSchool }"
|
||||||
upload-file-url="/purchase/purchasingfiles/upload"
|
upload-file-url="/purchase/purchasingfiles/upload"
|
||||||
:disabled="flowFieldDisabled('servicePublicSelectSchool')"
|
:disabled="flowFieldDisabled('servicePublicSelectSchool')"
|
||||||
@@ -751,7 +738,7 @@
|
|||||||
<upload-file
|
<upload-file
|
||||||
v-model="dataForm.purchaseRequirement"
|
v-model="dataForm.purchaseRequirement"
|
||||||
:limit="1"
|
:limit="1"
|
||||||
:file-type="['doc', 'docx', 'pdf']"
|
:file-type="['doc', 'docx', 'pdf', 'jpg', 'jpeg', 'png', 'gif', 'bmp', 'webp']"
|
||||||
:data="{ fileType: FILE_TYPE_MAP.purchaseRequirement }"
|
:data="{ fileType: FILE_TYPE_MAP.purchaseRequirement }"
|
||||||
upload-file-url="/purchase/purchasingfiles/upload"
|
upload-file-url="/purchase/purchasingfiles/upload"
|
||||||
:disabled="flowFieldDisabled('purchaseRequirement')"
|
:disabled="flowFieldDisabled('purchaseRequirement')"
|
||||||
@@ -773,7 +760,7 @@
|
|||||||
<upload-file
|
<upload-file
|
||||||
v-model="dataForm.governmentPurchaseIntent"
|
v-model="dataForm.governmentPurchaseIntent"
|
||||||
:limit="1"
|
:limit="1"
|
||||||
:file-type="['doc', 'docx', 'pdf']"
|
:file-type="['doc', 'docx', 'pdf', 'jpg', 'jpeg', 'png', 'gif', 'bmp', 'webp']"
|
||||||
:data="{ fileType: FILE_TYPE_MAP.governmentPurchaseIntent }"
|
:data="{ fileType: FILE_TYPE_MAP.governmentPurchaseIntent }"
|
||||||
upload-file-url="/purchase/purchasingfiles/upload"
|
upload-file-url="/purchase/purchasingfiles/upload"
|
||||||
:disabled="flowFieldDisabled('governmentPurchaseIntent')"
|
:disabled="flowFieldDisabled('governmentPurchaseIntent')"
|
||||||
@@ -1285,9 +1272,9 @@ const schoolUnifiedPurchaseFormDefault = computed(() => {
|
|||||||
// 申请阶段:始终可选(根据默认值自动选中后,允许用户自行修改)
|
// 申请阶段:始终可选(根据默认值自动选中后,允许用户自行修改)
|
||||||
// 流程嵌入:采购中心节点可编辑,其他节点只读
|
// 流程嵌入:采购中心节点可编辑,其他节点只读
|
||||||
const schoolUnifiedPurchaseFormDisabled = computed(() => {
|
const schoolUnifiedPurchaseFormDisabled = computed(() => {
|
||||||
if (!isFlowEmbed.value) {
|
// if (!isFlowEmbed.value) {
|
||||||
return false;
|
// return false;
|
||||||
}
|
// }
|
||||||
// 流程嵌入且为采购中心:放开编辑
|
// 流程嵌入且为采购中心:放开编辑
|
||||||
if (isPurchaseCenter.value) {
|
if (isPurchaseCenter.value) {
|
||||||
return false;
|
return false;
|
||||||
@@ -1610,6 +1597,7 @@ const dataRules = reactive({
|
|||||||
],
|
],
|
||||||
purchaseChannel: [
|
purchaseChannel: [
|
||||||
{
|
{
|
||||||
|
required: true,
|
||||||
validator: (_rule: any, value: string, callback: (e?: Error) => void) => {
|
validator: (_rule: any, value: string, callback: (e?: Error) => void) => {
|
||||||
if (!isDeptPurchase.value) {
|
if (!isDeptPurchase.value) {
|
||||||
callback();
|
callback();
|
||||||
|
|||||||
Reference in New Issue
Block a user