配置 eslint 与 prettier

This commit is contained in:
tao
2026-01-14 16:35:46 +08:00
parent 09b921009e
commit 317f2847ac
65 changed files with 6469 additions and 3487 deletions

View File

@@ -1,123 +1,155 @@
<template>
<div>
<template v-for="(item, index) in options">
<template v-if="isValueMatch(item.value)">
<span
v-if="(item.elTagType == 'default' || item.elTagType == '') && (item.elTagClass == '' || item.elTagClass == null)"
:key="item.value" :index="index" :class="item.elTagClass">{{ item.label + " " }}</span>
<a-tag v-else :disable-transitions="true" :key="item.value + ''" :index="index" :color="getColor(item.elTagType)"
:class="item.elTagClass + ' ' + size">{{ item.label + " " }}</a-tag>
</template>
</template>
<template v-if="unmatch && showValue">
{{ unmatchArray || handleArray }}
</template>
</div>
<div>
<template v-for="(item, index) in options">
<template v-if="isValueMatch(item.value)">
<span
v-if="
(item.elTagType == 'default' || item.elTagType == '') &&
(item.elTagClass == '' || item.elTagClass == null)
"
:key="item.value"
:index="index"
:class="item.elTagClass"
>
{{ item.label + ' ' }}
</span>
<a-tag
v-else
:disable-transitions="true"
:key="item.value + ''"
:index="index"
:color="getColor(item.elTagType)"
:class="item.elTagClass + ' ' + size"
>
{{ item.label + ' ' }}
</a-tag>
</template>
</template>
<template v-if="unmatch && showValue">
{{ unmatchArray || handleArray }}
</template>
</div>
</template>
<script setup lang="ts">
import { computed, ref } from 'vue'
interface DictOption {
label: string;
value: string;
elTagType?: string;
elTagClass?: string;
label: string
value: string
elTagType?: string
elTagClass?: string
}
// 记录未匹配的项
const unmatchArray = ref<any>([])
const props = defineProps({
// 数据
options: {
type: Array as () => Array<DictOption>,
default: null,
},
// 当前的值
value: [Number, String, Array],
// 当未找到匹配的数据时显示value
showValue: {
type: Boolean,
default: true,
},
separator: {
type: String,
default: ",",
},
size: {
type: String,
default: 'mini',
},
// 数据
options: {
type: Array as () => Array<DictOption>,
default: null,
},
// 当前的值
value: [Number, String, Array],
// 当未找到匹配的数据时显示value
showValue: {
type: Boolean,
default: true,
},
separator: {
type: String,
default: ',',
},
size: {
type: String,
default: 'mini',
},
})
const values = computed(() => {
if (props.value === null || typeof props.value === 'undefined' || props.value === '') return []
if (typeof props.value === 'number' || typeof props.value === 'boolean') return [props.value]
return Array.isArray(props.value) ? props.value.map(item => '' + item) : String(props.value).split(props.separator)
if (
props.value === null ||
typeof props.value === 'undefined' ||
props.value === ''
)
return []
if (typeof props.value === 'number' || typeof props.value === 'boolean')
return [props.value]
return Array.isArray(props.value)
? props.value.map((item) => '' + item)
: String(props.value).split(props.separator)
})
const unmatch = computed(() => {
unmatchArray.value = []
// 没有value不显示
if (props.value === null || typeof props.value === 'undefined' || props.value === '' || !Array.isArray(props.options) || props.options.length === 0) return false
// 传入值为数组
let unmatch = false // 添加一个标志来判断是否有未匹配项
values.value.forEach(item => {
if (!props.options.some(v => v.value == item)) {
unmatchArray.value.push(item)
unmatch = true // 如果有未匹配项将标志设置为true
}
})
return unmatch // 返回标志的值
// eslint-disable-next-line vue/no-side-effects-in-computed-properties
unmatchArray.value = []
// 没有value不显示
if (
props.value === null ||
typeof props.value === 'undefined' ||
props.value === '' ||
!Array.isArray(props.options) ||
props.options.length === 0
)
return false
// 传入值为数组
let unmatch = false // 添加一个标志来判断是否有未匹配项
values.value.forEach((item) => {
if (!props.options.some((v) => v.value == item)) {
unmatchArray.value.push(item)
unmatch = true // 如果有未匹配项将标志设置为true
}
})
return unmatch // 返回标志的值
})
function handleArray(array: string[]) {
if (array.length === 0) return ""
return array.reduce((pre, cur) => {
return pre + " " + cur
})
if (array.length === 0) return ''
return array.reduce((pre, cur) => {
return pre + ' ' + cur
})
}
function isValueMatch(itemValue: string) {
return values.value.some(val => val == itemValue)
return values.value.some((val) => val == itemValue)
}
function getColor(tagType: string | undefined) {
switch (tagType) {
case 'primary':
return 'processing'
case 'success':
return 'success'
case 'info':
return 'info'
case 'warning':
return 'warning'
case 'danger':
return 'error'
default:
return 'default'
}
switch (tagType) {
case 'primary':
return 'processing'
case 'success':
return 'success'
case 'info':
return 'info'
case 'warning':
return 'warning'
case 'danger':
return 'error'
default:
return 'default'
}
}
</script>
<style scoped>
.ant-tag+.ant-tag {
margin-left: 10px;
.ant-tag + .ant-tag {
margin-left: 10px;
}
.ant-tag{
&.large {
font-size: 18px;
line-height: 28px;
}
&.medium {
font-size: 16px;
line-height: 24px;
}
&.mini {
font-size: 12px;
line-height: 20px;
}
.ant-tag {
&.large {
font-size: 18px;
line-height: 28px;
}
&.medium {
font-size: 16px;
line-height: 24px;
}
&.mini {
font-size: 12px;
line-height: 20px;
}
}
</style>

View File

@@ -1,143 +1,160 @@
<template>
<header class="header-container" :class="{ 'hide-shadow': hideShadow }"
:style="{ height, zIndex, lineHeight: height }">
<div class="opts left-opts" v-if="$slots['left-opts'] || title || $slots.title">
<a-button v-if="showBack" @click="back">返回</a-button>
<a-button v-if="showHome" @click="backToHome">首页</a-button>
<slot name="left-opts" />
</div>
<div class="title" v-if="title || $slots.title">
<slot name="title">
{{ title }}
</slot>
</div>
<div class="opts right-opts" v-if="$slots['right-opts'] || title || $slots.title">
<slot name="right-opts" />
<a-button @click="handleLogout" type="primary" danger
v-if="showLogout && username">退出{{ username }}</a-button>
</div>
<slot />
</header>
<header
class="header-container"
:class="{ 'hide-shadow': hideShadow }"
:style="{ height, zIndex, lineHeight: height }"
>
<div
class="opts left-opts"
v-if="$slots['left-opts'] || title || $slots.title"
>
<a-button v-if="showBack" @click="back">返回</a-button>
<a-button v-if="showHome" @click="backToHome">首页</a-button>
<slot name="left-opts" />
</div>
<div class="title" v-if="title || $slots.title">
<slot name="title">
{{ title }}
</slot>
</div>
<div
class="opts right-opts"
v-if="$slots['right-opts'] || title || $slots.title"
>
<slot name="right-opts" />
<a-button
@click="handleLogout"
type="primary"
danger
v-if="showLogout && username"
>
退出{{ username }}
</a-button>
</div>
<slot />
</header>
</template>
<script setup lang="ts">
import { useRouter } from 'vue-router';
import { Modal } from 'ant-design-vue';
import { useAuthStore, useUserStore } from '@/store';
import { storeToRefs } from 'pinia';
import { useRouter } from 'vue-router'
import { Modal } from 'ant-design-vue'
import { useAuthStore, useUserStore } from '@/store'
import { storeToRefs } from 'pinia'
defineProps({
showHome: {
type: Boolean,
default: false,
},
showBack: {
type: Boolean,
default: false,
},
showLogout: {
type: Boolean,
default: true,
},
title: {
type: String,
default: null,
},
hideShadow: {
type: Boolean,
default: false
},
height: {
type: String,
default: '',
},
zIndex: {
type: Number,
default: 999,
}
});
showHome: {
type: Boolean,
default: false,
},
showBack: {
type: Boolean,
default: false,
},
showLogout: {
type: Boolean,
default: true,
},
title: {
type: String,
default: null,
},
hideShadow: {
type: Boolean,
default: false,
},
height: {
type: String,
default: '',
},
zIndex: {
type: Number,
default: 999,
},
})
defineSlots<{
'default'(): any;
'left-opts'(): any;
'title'(): any;
'right-opts'(): any;
}>();
'default'(): any
'left-opts'(): any
'title'(): any
'right-opts'(): any
}>()
const emit = defineEmits(['back']);
const router = useRouter();
const emit = defineEmits(['back'])
const router = useRouter()
const userStore = useUserStore();
const { username } = storeToRefs(userStore);
const userStore = useUserStore()
const { username } = storeToRefs(userStore)
const authStore = useAuthStore();
const authStore = useAuthStore()
const handleLogout = () => {
Modal.confirm({
title: '提示',
content: `是否确认退出登录:${ username.value }`,
okText: '确定',
cancelText: '取消',
onOk: () => {
authStore.logout();
},
});
};
Modal.confirm({
title: '提示',
content: `是否确认退出登录:${username.value}`,
okText: '确定',
cancelText: '取消',
onOk: () => {
authStore.logout()
},
})
}
const back = () => {
emit('back');
defaultBack();
};
emit('back')
defaultBack()
}
const defaultBack = () => {
router.go(-1);
};
router.go(-1)
}
const backToHome = () => {
router.push({ name: 'Index' });
};
router.push({ name: 'Index' })
}
</script>
<style scoped lang="scss">
.header-container {
width: 100%;
padding: 6px 1rem;
display: flex;
align-items: center;
gap: 10px;
background-color: #1f2e54;
color: #fff;
box-shadow: rgba(0, 0, 0, 0.1) 0px 4px 6px -1px, rgba(0, 0, 0, 0.06) 0px 2px 4px -1px;
width: 100%;
padding: 6px 1rem;
display: flex;
align-items: center;
gap: 10px;
background-color: #1f2e54;
color: #fff;
box-shadow:
rgba(0, 0, 0, 0.1) 0px 4px 6px -1px,
rgba(0, 0, 0, 0.06) 0px 2px 4px -1px;
&.hide-shadow {
box-shadow: none;
}
&.hide-shadow {
box-shadow: none;
}
.title {
flex: 14;
color: #fff;
white-space: nowrap;
overflow: hidden;
text-align: center;
text-overflow: ellipsis;
font-size: clamp(16px, 2.5vw, 32px);
font-weight: bold;
}
.title {
flex: 14;
color: #fff;
white-space: nowrap;
overflow: hidden;
text-align: center;
text-overflow: ellipsis;
font-size: clamp(16px, 2.5vw, 32px);
font-weight: bold;
}
.opts {
height: 100%;
flex: 5;
display: flex;
align-items: center;
flex-shrink: 0;
gap: 8px;
.opts {
height: 100%;
flex: 5;
display: flex;
align-items: center;
flex-shrink: 0;
gap: 8px;
&.left-opts {
justify-content: flex-start;
}
&.left-opts {
justify-content: flex-start;
}
&.right-opts {
justify-content: flex-end;
}
}
&.right-opts {
justify-content: flex-end;
}
}
}
</style>

View File

@@ -1,45 +1,46 @@
<template>
<div class="title">
<span>{{ name }}</span>
<a-space class="subtitle">
<slot />
<a-button v-if="showRefresh" size="small" @click="handleRefresh">
<template #icon><i-lucide-rotate-ccw /></template>刷新
</a-button>
</a-space>
</div>
<div class="title">
<span>{{ name }}</span>
<a-space class="subtitle">
<slot />
<a-button v-if="showRefresh" size="small" @click="handleRefresh">
<template #icon><i-lucide-rotate-ccw /></template>
刷新
</a-button>
</a-space>
</div>
</template>
<script setup lang="ts">
defineProps({
name: {
type: String,
default: '',
},
showRefresh: {
type: Boolean,
default: false,
},
});
name: {
type: String,
default: '',
},
showRefresh: {
type: Boolean,
default: false,
},
})
const slots = defineSlots<{
'default'(): any;
}>();
defineSlots<{
'default'(): any
}>()
const emit = defineEmits(['refresh']);
const emit = defineEmits(['refresh'])
const handleRefresh = () => {
emit('refresh');
};
emit('refresh')
}
</script>
<style scoped lang="scss">
.title {
display: flex;
align-items: center;
justify-content: space-between;
font-size: 20px;
font-weight: 600;
border-bottom: 1px solid #c9c9c9;
padding-bottom: 7px;
display: flex;
align-items: center;
justify-content: space-between;
font-size: 20px;
font-weight: 600;
border-bottom: 1px solid #c9c9c9;
padding-bottom: 7px;
}
</style>

View File

@@ -1,82 +1,101 @@
<template>
<a-button class="action-btn" @click="handleHold">Hold</a-button>
<a-button class="action-btn" @click="handleHold">Hold</a-button>
<!-- Hold Modal -->
<a-modal v-model:open="openHoldModal" title="Hold 操作" @cancel="handleCloseHold" @ok="handleSubmitHold">
<a-form :colon="false" :label-col="{ span: 6 }" :wrapper-col="{ span: 18 }">
<a-form-item label="工单编码">
<a-input v-model:value="traceOrderStore.traceOrderInfo.code" readonly />
</a-form-item>
<a-form-item label="目标产品编码">
<a-input v-model:value="traceOrderStore.traceOrderInfo.tarMaterialCode" readonly />
</a-form-item>
<a-form-item label="目标产品名称">
<a-input v-model:value="traceOrderStore.traceOrderInfo.tarMaterialName" readonly />
</a-form-item>
<a-form-item label="发起工序名称">
<a-input v-model:value="traceOrderStore.stationInfo.operationTitle" readonly />
</a-form-item>
<a-form-item label="产品规格">
<a-input readonly />
</a-form-item>
<a-form-item label="计划完成日期">
<a-date-picker v-model:value="planFinishDate" placeholder="选择计划完成日期" valueFormat="YYYY-MM-DD HH:mm:ss" show-time
style="width: 100%" />
</a-form-item>
</a-form>
</a-modal>
<!-- Hold Modal -->
<a-modal
v-model:open="openHoldModal"
title="Hold 操作"
@cancel="handleCloseHold"
@ok="handleSubmitHold"
>
<a-form :colon="false" :label-col="{ span: 6 }" :wrapper-col="{ span: 18 }">
<a-form-item label="工单编码">
<a-input v-model:value="traceOrderStore.traceOrderInfo.code" readonly />
</a-form-item>
<a-form-item label="目标产品编码">
<a-input
v-model:value="traceOrderStore.traceOrderInfo.tarMaterialCode"
readonly
/>
</a-form-item>
<a-form-item label="目标产品名称">
<a-input
v-model:value="traceOrderStore.traceOrderInfo.tarMaterialName"
readonly
/>
</a-form-item>
<a-form-item label="发起工序名称">
<a-input
v-model:value="traceOrderStore.stationInfo.operationTitle"
readonly
/>
</a-form-item>
<a-form-item label="产品规格">
<a-input readonly />
</a-form-item>
<a-form-item label="计划完成日期">
<a-date-picker
v-model:value="planFinishDate"
placeholder="选择计划完成日期"
valueFormat="YYYY-MM-DD HH:mm:ss"
show-time
style="width: 100%"
/>
</a-form-item>
</a-form>
</a-modal>
</template>
<script setup lang="ts">
import { ref } from 'vue';
import { useDialog } from '@/utils/useDialog';
import { useTraceOrderStore } from '@/store';
import { message } from 'ant-design-vue';
import { addQualityAbnormalContact } from '@/api/traceOrderManage';
import { ref } from 'vue'
import { useDialog } from '@/utils/useDialog'
import { useTraceOrderStore } from '@/store'
import { message } from 'ant-design-vue'
import { addQualityAbnormalContact } from '@/api/traceOrderManage'
const traceOrderStore = useTraceOrderStore();
const traceOrderStore = useTraceOrderStore()
// useDialog 管理弹窗状态
const { visible: openHoldModal, show, hide } = useDialog();
const { visible: openHoldModal, show, hide } = useDialog()
const planFinishDate = ref('');
const planFinishDate = ref('')
const handleHold = () => {
if (!traceOrderStore.currentTraceOrderCode) {
message.error('请先选择工单!');
return;
}
show();
};
if (!traceOrderStore.currentTraceOrderCode) {
message.error('请先选择工单!')
return
}
show()
}
const handleCloseHold = () => {
planFinishDate.value = '';
hide();
};
planFinishDate.value = ''
hide()
}
const handleSubmitHold = async () => {
const tmpPlanFinishDate = planFinishDate.value;
// 修改随工单状态
try {
message.success('Hold 成功!')
planFinishDate.value = '';
openHoldModal.value = false;
} catch (error: any) {
message.error(error.message || 'Hold 失败');
return;
}
const tmpPlanFinishDate = planFinishDate.value
// 修改随工单状态
try {
message.success('Hold 成功!')
planFinishDate.value = ''
openHoldModal.value = false
} catch (error: any) {
message.error(error.message || 'Hold 失败')
return
}
// 添加修改记录
try {
addQualityAbnormalContact({
materialCode: traceOrderStore.traceOrderInfo.tarMaterialCode,
abnormalOperation: traceOrderStore.stationInfo.operationCode,
planFinishDate: tmpPlanFinishDate,
status: "Hold",
})
} catch (error: any) {
message.error(error.message || '添加记录异常');
return;
}
};
// 添加修改记录
try {
addQualityAbnormalContact({
materialCode: traceOrderStore.traceOrderInfo.tarMaterialCode,
abnormalOperation: traceOrderStore.stationInfo.operationCode,
planFinishDate: tmpPlanFinishDate,
status: 'Hold',
})
} catch (error: any) {
message.error(error.message || '添加记录异常')
return
}
}
</script>