| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478 |
- <template>
- <div id="algoCardWrapper" class="algoCardWrapper">
- <div class="algoCardTitle">
- <div>算法参数</div>
- </div>
- <div class="algoCardMain">
- <div style="display: flex">
- <div style="margin-right: 30px; display: flex; margin-top: 16px">
- <div class="algoLabel">检测元数据:</div>
- <div class="algoTimeContent">
- <div
- class="timeAdd"
- :class="{ addDisable: unEmptyLabels.length >= metaObjList.length }"
- @click="handleAddMetaObj"
- >
- <el-icon color="#d0d0d0"><Plus /></el-icon>
- </div>
- <div class="metaValuesList">
- <AlgoParamsCard
- v-for="(v, index) in selectedAlgoDetail.metaValues"
- :key="v.id"
- :ref="(el) => (paramCardRefs[index] = el)"
- :id="v.id"
- @change="handleChange"
- />
- </div>
- </div>
- </div>
- <div>
- <div class="algoRow" style="align-items: center">
- <div class="algoLabel">检测数量范围:</div>
- <el-radio-group v-model="selectedAlgoDetail.judge" class="ml-4" @change="handleChange">
- <el-radio :label="0">小于</el-radio>
- <el-radio :label="1">大于</el-radio>
- <el-radio :label="2">等于</el-radio>
- </el-radio-group>
- </div>
- <div class="algoRow" style="align-items: center">
- <div class="algoLabel">检测频率:</div>
- <ElInputNumber
- v-model="selectedAlgoDetail.detectionFrequency"
- controls-position="right"
- :min="1"
- :step="1"
- size="small"
- style="width: 186px"
- @blur="checkFrequencyValid"
- @change="handleChange"
- />
- <span style="font-size: 12px; margin-left: 5px">S/次</span>
- </div>
- <div class="algoRow" style="align-items: center">
- <div class="algoLabel">持续时间:</div>
- <ElInputNumber
- v-model="selectedAlgoDetail.eventDurationMinMs"
- controls-position="right"
- :min="1"
- :step="1"
- size="small"
- style="width: 186px"
- @blur="checkDurationMinMsValid"
- @change="handleChange"
- />
- <span style="font-size: 12px; margin-left: 5px">毫秒</span>
- </div>
- <div class="algoRow" style="align-items: center">
- <div class="algoLabel">持续帧数:</div>
- <ElInputNumber
- v-model="selectedAlgoDetail.eventDurationMinFrames"
- controls-position="right"
- :min="1"
- :step="1"
- size="small"
- style="width: 186px"
- @blur="checkDurationMinFramesValid"
- @change="handleChange"
- />
- <span style="font-size: 12px; margin-left: 5px">帧</span>
- </div>
- <div class="algoRow" style="align-items: center">
- <div class="algoLabel">报警时间间隔:</div>
- <ElInputNumber
- v-model="selectedAlgoDetail.eventAlarmIntervalMs"
- controls-position="right"
- :min="1"
- :step="1"
- size="small"
- style="width: 186px"
- @blur="checkAlarmIntervalMsValid"
- @change="handleChange"
- />
- <span style="font-size: 12px; margin-left: 5px">秒</span>
- </div>
- <div class="algoRow" style="align-items: center">
- <div class="algoLabel">报警帧间隔:</div>
- <ElInputNumber
- v-model="selectedAlgoDetail.eventAlarmIntervalFrames"
- controls-position="right"
- :min="1"
- :step="1"
- size="small"
- style="width: 186px"
- @blur="checkAlarmIntervalFramesValid"
- @change="handleChange"
- />
- <span style="font-size: 12px; margin-left: 5px">帧</span>
- </div>
- </div>
- </div>
- <div v-if="selectedAlgoDetail.timeWindow !== undefined" class="algoRow" style="align-items: center">
- <div class="algoLabel">检测窗口时长:</div>
- <ElInputNumber
- v-model="selectedAlgoDetail.timeWindow"
- controls-position="right"
- :min="1"
- size="small"
- style="width: 186px"
- placeholder="请输入允许的最长时间"
- @blur="checkTimeWindowValid"
- @change="handleChange"
- />
- <span style="font-size: 12px; margin-left: 5px">S</span>
- </div>
- <div class="algoRow" style="margin-top: 20px">
- <div class="algoLabel">检测时间段:</div>
- <div class="algoTimeContent">
- <div class="timeAdd" @click="handleAddTimePeriod">
- <el-icon color="#d0d0d0"><Plus /></el-icon>
- </div>
- <div class="timeList" v-if="selectedAlgoDetail.timeRangeArr?.length > 0">
- <PeriodCard
- v-for="(x, index) in selectedAlgoDetail.timeRangeArr"
- :key="x.id"
- :ref="(el) => (periodCardRefs[index] = el)"
- :id="x.id"
- @change="handleChange"
- />
- </div>
- </div>
- </div>
- <div style="display: flex; justify-content: flex-end">
- <ElButton size="small" @click="handleRemoveAlgo">取消</ElButton>
- <ElButton size="small" type="primary" @click="handleSave">保存</ElButton>
- </div>
- </div>
- </div>
- </template>
- <script lang="ts" setup>
- import { ElInputNumber, ElMessage, ElMessageBox } from 'element-plus';
- import { Plus } from '@element-plus/icons-vue';
- import { storeToRefs } from 'pinia';
- // import useCameraAlgoStore, { AlgoParamMetaItem } from './store/useCameraAlgoStore';
- import useAlgoParamsSettingStore from './use-algo-params-edit-store';
- import { AlgoParamMetaItem, CameraAlgoItemInCard } from './types';
- import { createDefaultTime, getTimeCompletion } from './utils';
- import { ALGO_ENABLED_STATUS, FENCE_ENBALED_STATUS } from '@/api/camera/camera-preview';
- import PeriodCard from './AlgoPeriodCard.vue';
- import AlgoParamsCard from './AlgoParamsCard.vue';
- import { uid } from 'uid';
- import { computed, onMounted, onUnmounted, ref } from 'vue';
- // const { data: algoList, loading } = useAllAlgos();
- const algoParamsSettingStore = useAlgoParamsSettingStore();
- const { selectedAlgoDetail, metaObjList, markedTimeRangeIds, markedParamCardIds } =
- storeToRefs(algoParamsSettingStore);
- interface Param {
- /** 算法id */
- algoId: number;
- /** 检测频率,单位是秒 */
- detectionFrequency: number;
- /** 检测时间段,可以有多个,转化为字符串,格式为 09:00-10:00;11:00-12:00 */
- detectionTime: string;
- /** 电子围栏是否开启 */
- electronicFence: FENCE_ENBALED_STATUS;
- /** 算法是否启用 */
- status: ALGO_ENABLED_STATUS;
- }
- const props = defineProps<{
- isChanged?: boolean;
- algoDetail: CameraAlgoItemInCard;
- }>();
- const emits = defineEmits<{
- (e: 'onSubmit', param: Param): Promise<unknown>;
- (e: 'onCancel'): Promise<unknown>;
- (e: 'change'): unknown;
- }>();
- const periodCardRefs = ref<any>([]);
- const paramCardRefs = ref<any>([]);
- onMounted(() => {
- selectedAlgoDetail.value = { ...props.algoDetail };
- });
- const handleChange = () => {
- emits('change');
- };
- const handleAddTimePeriod = () => {
- const emptyList = selectedAlgoDetail.value.timeRangeArr?.filter((item) => !getTimeCompletion(item));
- if (emptyList && emptyList.length > 0) {
- emptyList.forEach((item) => markedTimeRangeIds.value.push(item.id));
- ElMessage.error('请先完善检测时间段数据');
- return;
- }
- handleChange();
- selectedAlgoDetail.value.timeRangeArr?.push(createDefaultTime());
- };
- const unEmptyLabels = computed(() => {
- return selectedAlgoDetail.value.metaValues?.filter((item) => item.label) || [];
- });
- const handleAddMetaObj = () => {
- if (unEmptyLabels.value.length < selectedAlgoDetail.value.metaValues?.length) {
- selectedAlgoDetail.value.metaValues
- .filter((item) => !item.label)
- .forEach((val) => markedParamCardIds.value.push(val.id));
- ElMessage.error('存在未完善的检测元数据');
- return;
- }
- handleChange();
- // if (unemptyList.length == metaObjList.value.length) {
- // ElMessage.warning('暂无更多检测对象');
- // return;
- // }
- selectedAlgoDetail.value.metaValues.push({ id: uid() } as AlgoParamMetaItem);
- };
- const checkFrequencyValid = () => {
- selectedAlgoDetail.value.detectionFrequency = Math.ceil(selectedAlgoDetail.value.detectionFrequency);
- };
- const checkDurationMinMsValid = () => {
- selectedAlgoDetail.value.eventDurationMinMs = Math.ceil(selectedAlgoDetail.value.eventDurationMinMs);
- };
- const checkDurationMinFramesValid = () => {
- selectedAlgoDetail.value.eventDurationMinFrames = Math.ceil(selectedAlgoDetail.value.eventDurationMinFrames);
- };
- const checkAlarmIntervalMsValid = () => {
- selectedAlgoDetail.value.eventAlarmIntervalMs = Math.ceil(selectedAlgoDetail.value.eventAlarmIntervalMs);
- };
- const checkAlarmIntervalFramesValid = () => {
- selectedAlgoDetail.value.eventAlarmIntervalFrames = Math.ceil(selectedAlgoDetail.value.eventAlarmIntervalFrames);
- };
- const checkTimeWindowValid = () => {
- selectedAlgoDetail.value.timeWindow = Math.ceil(selectedAlgoDetail.value.timeWindow || 1);
- };
- const handleSave = async () => {
- //判断时间段是否合格
- if (markedTimeRangeIds.value.length > 0) {
- ElMessage.error('请正确填写检测时间段');
- return;
- }
- const emptyTimes = selectedAlgoDetail.value.timeRangeArr.filter((item) => !item.startDay || !item.endDay);
- if (emptyTimes && emptyTimes.length > 0) {
- emptyTimes.forEach((item) => {
- markedTimeRangeIds.value.push(item.id);
- });
- ElMessage.error('请完善检测时间段');
- return;
- }
- for (let i = 0; i < periodCardRefs.value.length; i++) {
- const item = periodCardRefs.value[i];
- if (!item) continue;
- switch (item.checkValid()) {
- case 0:
- ElMessage.error('请正确填写检测时间段');
- return;
- case 1:
- ElMessage.error('请完善检测时间段');
- return;
- case 2:
- ElMessage.error('至少有一个时间段');
- return;
- case 3:
- break;
- }
- }
- //判断元数据是否合格
- for (let i = 0; i < paramCardRefs.value.length; i++) {
- const item = paramCardRefs.value[i];
- if (!item) continue;
- const res = await item.checkValid();
- if (res) {
- } else {
- ElMessage.error('请正确填写检测元数据');
- return;
- }
- }
- //判断时间段和元数据都有值
- const detail = selectedAlgoDetail.value;
- if (!detail) return;
- // const timeRanges = detail.timeRangeArr;
- // if (timeRanges.length == 0) {
- // ElMessage.error('至少添加一个检测时间段');
- // return;
- // }
- const metaValues = detail.metaValues;
- // 鹰眼追踪不需要元数据,先放开所有算法的元数据约束
- // if (metaValues.length == 0) {
- // ElMessage.error('至少添加一个检测元数据');
- // return;
- // }
- //数据处理
- const metaObjs = metaValues.map((meta) => {
- const obj = metaObjList.value.find((item) => item.label === meta.label);
- const val = {
- label: meta.label,
- confidence: meta.confidence / 100,
- min_width: meta['min_width'],
- min_height: meta['min_height'],
- } as any;
- const nextValues = [] as any[];
- obj.nextObjs.forEach((next) => {
- if (meta[`${next.label}.confidence`]) {
- nextValues.push({
- label: next.label,
- confidence: meta[`${next.label}.confidence`] / 100,
- min_width: meta[next.label + '.' + 'min_width'],
- min_height: meta[next.label + '.' + 'min_height'],
- nextObjs: [],
- });
- }
- });
- val.nextObjs = nextValues;
- return val;
- });
- const param = {
- id: detail.id,
- inferCode: detail.inferCode,
- algoId: detail.algoId,
- detectionFrequency: detail.detectionFrequency,
- eventDurationMinMs: detail.eventDurationMinMs,
- eventDurationMinFrames: detail.eventDurationMinFrames,
- eventAlarmIntervalMs: detail.eventAlarmIntervalMs,
- eventAlarmIntervalFrames: detail.eventAlarmIntervalFrames,
- regionJudge: detail.regionJudge,
- detectionTime: JSON.stringify(detail.timeRangeArr),
- metaObjs,
- criticalCounts: metaValues.map((item) => item.criticalCount),
- judge: detail.judge,
- electronicFence: detail.electronicFenceBool ? FENCE_ENBALED_STATUS.enabled : FENCE_ENBALED_STATUS.disabled,
- status: detail.enableCardBool ? ALGO_ENABLED_STATUS.enabled : ALGO_ENABLED_STATUS.disabled,
- } as any;
- if (detail.timeWindow) {
- param.timeWindow = detail.timeWindow;
- }
- emits('onSubmit', param);
- console.log('param', param);
- };
- const handleRemoveAlgo = () => {
- const el = document.getElementById('algoCardWrapper') as HTMLElement;
- if (props.isChanged) {
- ElMessageBox.confirm('<strong>确认取消算法配置吗?</strong><br />取消后配置的参数将不会被保存。', '', {
- confirmButtonText: '确定',
- cancelButtonText: '取消',
- type: 'warning',
- dangerouslyUseHTMLString: true,
- appendTo: el,
- })
- .then(() => {
- emits('onCancel');
- })
- .catch(() => {});
- } else {
- emits('onCancel');
- }
- };
- onUnmounted(() => {
- algoParamsSettingStore.clear();
- });
- </script>
- <style scoped>
- .algoCardWrapper {
- border: 1px solid #ccc;
- border-radius: 4px;
- /* padding: 10px; */
- width: 990px;
- }
- .algoRow {
- display: flex;
- margin: 10px 0;
- }
- .algoLabel {
- margin-right: 10px;
- width: 90px;
- text-align: right;
- flex-shrink: 0;
- flex-grow: 0;
- }
- .algoTimeContent {
- display: flex;
- }
- .presetList {
- font-size: 12px;
- display: none;
- }
- .removeIcon {
- margin-left: 10px;
- color: #8c8c8c;
- cursor: pointer;
- }
- .addTimeIcon {
- cursor: pointer;
- }
- .algoCardTitle {
- background: #f0f2f5;
- display: flex;
- justify-content: space-between;
- padding: 4px 20px;
- align-items: center;
- }
- .algoCardMain {
- padding: 10px 15px;
- }
- .timeAdd {
- width: 28px;
- height: 50px;
- background: #ebebeb;
- border-radius: 4px;
- border: 1px dashed #00000026;
- display: flex;
- justify-content: center;
- align-items: center;
- margin-right: 5px;
- cursor: pointer;
- }
- .addDisable {
- opacity: 0.5;
- cursor: not-allowed;
- }
- .timeList {
- overflow-y: auto;
- display: flex;
- flex-wrap: wrap;
- align-items: flex-start;
- }
- .metaValuesList {
- width: 425px;
- max-height: 350px;
- overflow-y: auto;
- display: flex;
- flex-wrap: wrap;
- align-items: flex-start;
- }
- .tipIcon {
- margin-left: 10px;
- }
- :deep(.ml-4) {
- margin-left: 0 !important;
- }
- :deep(.el-message-box__status.el-icon) {
- top: 0 !important;
- transform: none !important;
- }
- </style>
|