Skip to content

Commit

Permalink
* replace props.modelValue & emits.update:ModelValue with `define…
Browse files Browse the repository at this point in the history
…Model()`

* directly pass through `v-model="modelValue"` to the root element `<select>`
- remove unnecessary validation around `($event.target as HTMLSelectElement).value` since it should always be a string on modern browsers @ `<TimeGranularity>`, `<SelectRange>`, `<InputTextMatchParam>`

* fix the value of `inputName` losing reactivity from props @ `<InputTextMatchParam>`
* rename `props.placeholders.single` to `equals` @ `<InputNumericParam>`
* enable `options.inheritAttrs` to remove the optional prop `id` and force its usages explicitly set it @ `<Time(Range|Granularity)>`
* remove `readonly` modifier on type of `props.granularities` over its usage @ `<TimeGranularity>`
* now will validate the value of emitting event `paramChange` over pre-defined keys in `paramsGroup` @ `<SelectParam>`

* rename exported `emitEventNumValidator()` to `emitEventWithNumberValidator()`
- no longer used `emitEventStrValidator()`
@ shared/index.ts

* opt-in experimental `defineModel()` marco: vuejs/rfcs#503 @ vite.config.ts
@ fe
  • Loading branch information
n0099 committed Dec 17, 2023
1 parent c394f26 commit 1403ed2
Show file tree
Hide file tree
Showing 11 changed files with 50 additions and 59 deletions.
8 changes: 4 additions & 4 deletions fe/src/components/Post/queryForm/QueryForm.vue
Expand Up @@ -97,7 +97,7 @@
<InputNumericParam @update:modelValue="v => params[pI] = v"
:modelValue="params[pI] as KnownNumericParams"
:paramIndex="pI"
:placeholders="{ IN: '100,101,102,...', BETWEEN: '100,200', single: '100' }" />
:placeholders="{ IN: '100,101,102,...', BETWEEN: '100,200', equals: '100' }" />
</template>
<div v-if="p.name === 'threadProperties'">
<div class="param-input-group-text input-group-text">
Expand Down Expand Up @@ -142,7 +142,7 @@
<SelectRange v-model="p.subParam.range" />
<InputNumericParam @update:modelValue="v => params[pI] = v"
:modelValue="params[pI] as KnownNumericParams"
:placeholders="{ IN: '9,10,11,...', BETWEEN: '9,18', single: '18' }" />
:placeholders="{ IN: '9,10,11,...', BETWEEN: '9,18', equals: '18' }" />
</template>
</div>
</div>
Expand Down Expand Up @@ -215,12 +215,12 @@ const isPostIDParam = (param: Param): param is AddNameToParam<PostID, NamelessPa
const getPostIDParamPlaceholders = (p: Param) => ({
IN: p.name === 'tid' ? '5000000000,5000000001,5000000002,...' : '15000000000,15000000001,15000000002,...',
BETWEEN: p.name === 'tid' ? '5000000000,6000000000' : '15000000000,16000000000',
single: p.name === 'tid' ? '5000000000' : '15000000000'
equals: p.name === 'tid' ? '5000000000' : '15000000000'
});
const uidParamPlaceholders = {
IN: '4000000000,4000000001,4000000002,...',
BETWEEN: '4000000000,5000000000',
single: '4000000000'
equals: '4000000000'
};
const getCurrentQueryType = () => {
Expand Down
12 changes: 5 additions & 7 deletions fe/src/components/Post/queryForm/widgets/InputNumericParam.vue
Expand Up @@ -8,7 +8,7 @@
:placeholder="placeholders.BETWEEN" :aria-label="modelValue.name"
type="text" class="col-3 form-control flex-grow-0" required pattern="\d+,\d+" />
<input v-else @input="emitModelChange" :value="modelValue.value"
:placeholder="placeholders.single" :aria-label="modelValue.name"
:placeholder="placeholders.equals" :aria-label="modelValue.name"
type="number" class="col-2 form-control flex-grow-0" required />
</template>

Expand All @@ -17,18 +17,16 @@ import type { KnownNumericParams } from '../queryParams';
import { numericParamSubParamRangeValues } from '../queryParams';
import _ from 'lodash';
const props = defineProps<{
modelValue: KnownNumericParams,
placeholders: { [P in 'BETWEEN' | 'IN' | 'single']: string }
}>();
const emit = defineEmits({
defineProps<{ placeholders: { [P in 'BETWEEN' | 'IN' | 'equals']: string } }>();
defineEmits({
'update:modelValue': (p: KnownNumericParams) =>
_.isString(p.name) && _.isString(p.value)
&& numericParamSubParamRangeValues.includes(p.subParam.range)
});
const modelValue = defineModel<KnownNumericParams>({ required: true });
const emitModelChange = (e: Event) => {
emit('update:modelValue', { ...props.modelValue, value: (e.target as HTMLInputElement).value });
modelValue.value = { ...modelValue.value, value: (e.target as HTMLInputElement).value };
};
</script>

Expand Down
22 changes: 11 additions & 11 deletions fe/src/components/Post/queryForm/widgets/InputTextMatchParam.vue
Expand Up @@ -43,34 +43,34 @@ export const inputTextMatchParamPlaceholder = (p: KnownTextParams) =>
</script>

<script setup lang="ts">
import { computed } from 'vue';
import { textParamSubParamMatchByValues } from '../queryParams';
import type { KnownTextParams, NamelessParamText } from '../queryParams';
import type { ObjValues } from '@/shared';
import _ from 'lodash';
const props = defineProps<{
modelValue: KnownTextParams,
paramIndex: number
}>();
const emit = defineEmits({
const props = defineProps<{ paramIndex: number }>();
defineEmits({
'update:modelValue': (p: KnownTextParams) =>
_.isString(p.name) && _.isString(p.value)
&& textParamSubParamMatchByValues.includes(p.subParam.matchBy)
&& _.isBoolean(p.subParam.spaceSplit)
});
const modelValue = defineModel<KnownTextParams>({ required: true });
const emitModelChange = (
name: keyof NamelessParamText['subParam'],
value: ObjValues<NamelessParamText['subParam']>
) => {
emit('update:modelValue', {
...props.modelValue,
subParam: { ...props.modelValue.subParam, [name]: value }
} as KnownTextParams);
modelValue.value = {
...modelValue.value,
subParam: { ...modelValue.value.subParam, [name]: value }
} as KnownTextParams;
};
const inputID = (type: 'Explicit' | 'Implicit' | 'Regex' | 'SpaceSplit') =>
`param${_.upperFirst(props.modelValue.name)}${type}-${props.paramIndex}`;
const inputName = `param${_.upperFirst(props.modelValue.name)}-${props.paramIndex}`;
`param${_.upperFirst(modelValue.value.name)}${type}-${props.paramIndex}`;
const inputName = computed(() =>
`param${_.upperFirst(modelValue.value.name)}-${props.paramIndex}`);
</script>

<style scoped>
Expand Down
16 changes: 9 additions & 7 deletions fe/src/components/Post/queryForm/widgets/SelectParam.vue
Expand Up @@ -9,13 +9,7 @@
</select>
</template>

<script setup lang="ts">
import { emitEventStrValidator } from '@/shared';
import { ref, watchEffect } from 'vue';
const props = defineProps<{ currentParam: string }>();
defineEmits({ paramChange: emitEventStrValidator });
<script lang="ts">
const paramsGroup = {
帖子ID: {
tid: 'tid(主题帖ID)',
Expand Down Expand Up @@ -50,6 +44,14 @@ const paramsGroup = {
authorExpGrade: '发帖人经验等级'
}
};
</script>

<script setup lang="ts">
import { ref, watchEffect } from 'vue';
import _ from 'lodash';
const props = defineProps<{ currentParam: string }>();
defineEmits({ paramChange: p => _.includes(_.flatMap(paramsGroup, Object.keys), p) });
const selected = ref('add');
watchEffect(() => { selected.value = props.currentParam });
Expand Down
8 changes: 2 additions & 6 deletions fe/src/components/Post/queryForm/widgets/SelectRange.vue
@@ -1,6 +1,5 @@
<template>
<select @input="$emit('update:modelValue', ($event.target as HTMLSelectElement).value)" :value="modelValue"
class="form-select form-control flex-grow-0">
<select v-model="modelValue" class="form-select form-control flex-grow-0">
<option>&lt;</option>
<option>=</option>
<option>&gt;</option>
Expand All @@ -10,10 +9,7 @@
</template>

<script setup lang="ts">
import { emitEventStrValidator } from '@/shared';
withDefaults(defineProps<{ modelValue?: string }>(), { modelValue: '=' });
defineEmits({ 'update:modelValue': emitEventStrValidator });
const modelValue = defineModel({ default: '=' });
</script>

<style scoped>
Expand Down
15 changes: 4 additions & 11 deletions fe/src/components/widgets/TimeGranularity.vue
@@ -1,24 +1,17 @@
<template>
<select @input="$emit('update:modelValue', ($event.target as HTMLSelectElement).value)"
:id="id" :value="modelValue" class="form-control">
<select v-model="modelValue" class="form-control">
<option v-for="(text, granularity) in options" :key="granularity" :value="granularity">{{ text }}</option>
</select>
</template>

<script setup lang="ts">
import { emitEventStrValidator } from '@/shared';
import type { TimeGranularitiesStringMap } from '@/shared/echarts';
import { ref } from 'vue';
import _ from 'lodash';
const props = withDefaults(defineProps<{
modelValue: string,
id?: string,
granularities: readonly string[]
}>(), { id: 'queryTimeGranularity' });
defineEmits({
'update:modelValue': emitEventStrValidator
});
defineOptions({ inheritAttrs: true });
const props = defineProps<{ granularities: string[] }>();
const modelValue = defineModel<string>();
const defaultOptions: TimeGranularitiesStringMap = {
minute: '分钟',
Expand Down
11 changes: 5 additions & 6 deletions fe/src/components/widgets/TimeRange.vue
@@ -1,6 +1,6 @@
<template>
<RangePicker @change="(value, _) => timeRangeChanged(value as [Dayjs, Dayjs])"
:id="id" :value="timeRange" :ranges="{
:value="timeRange" :ranges="{
昨天: [dayjs().subtract(1, 'day').startOf('day'), dayjs().subtract(1, 'day').endOf('day')],
今天: [dayjs().startOf('day'), dayjs().endOf('day')],
本周: [dayjs().startOf('week'), dayjs().endOf('week')],
Expand All @@ -15,27 +15,26 @@
</template>

<script setup lang="ts">
import { emitEventNumValidator } from '@/shared';
import { emitEventWithNumberValidator } from '@/shared';
import { ref, watchEffect } from 'vue';
import { RangePicker } from 'ant-design-vue';
import type { DurationLike } from 'luxon';
import { DateTime } from 'luxon';
import type { Dayjs } from 'dayjs';
import dayjs, { unix } from 'dayjs';
defineOptions({ inheritAttrs: true });
const props = withDefaults(defineProps<{
id?: () => string,
startTime?: number,
endTime?: number,
timesAgo: DurationLike
}>(), {
id: () => 'queryTimeRange',
startTime: 0,
endTime: 0
});
const emit = defineEmits({
'update:startTime': emitEventNumValidator,
'update:endTime': emitEventNumValidator
'update:startTime': emitEventWithNumberValidator,
'update:endTime': emitEventWithNumberValidator
});
const timeRange = ref<[Dayjs, Dayjs]>([dayjs(), dayjs()]);
Expand Down
3 changes: 1 addition & 2 deletions fe/src/shared/index.ts
Expand Up @@ -52,5 +52,4 @@ export const boolPropToStr = <T>(object: Record<string, T | boolean>): Record<st
export const boolStrToBool = <T>(s: T | 'false' | 'true'): boolean => s === 'true';
export const boolStrPropToBool = <T>(object: Record<string, T | string>): Record<string, T | boolean | string> =>
_.mapValues(object, i => (_.includes(['true', 'false'], i) ? boolStrToBool(i) : i));
export const emitEventStrValidator = (p: string) => _.isString(p);
export const emitEventNumValidator = (p: number) => _.isNumber(p);
export const emitEventWithNumberValidator = (p: number) => _.isNumber(p);
6 changes: 4 additions & 2 deletions fe/src/views/Stats.vue
Expand Up @@ -22,14 +22,15 @@
<span class="input-group-text"><FontAwesomeIcon icon="calendar-alt" /></span>
<TimeRange v-model:startTime="query.startTime"
v-model:endTime="query.endTime"
:timesAgo="{ day: 14 }" />
id="queryTimeRange" :timesAgo="{ day: 14 }" />
</div>
</div>
<label class="col-1 col-form-label text-end" for="queryTimeGranularity">时间粒度</label>
<div class="col-2">
<div class="input-group">
<span class="input-group-text"><FontAwesomeIcon icon="clock" /></span>
<TimeGranularity v-model="query.timeGranularity" :granularities="timeGranularities" />
<TimeGranularity v-model="query.timeGranularity" id="queryTimeGranularity"
:granularities="timeGranularities as Writable<typeof timeGranularities>" />
</div>
</div>
</div>
Expand All @@ -45,6 +46,7 @@ import type { ApiForumList, ApiStatsForumPostCountQueryParam } from '@/api/index
import { apiForumList, apiStatsForumsPostCount, throwIfApiError } from '@/api';
import { emptyChartSeriesData, extendCommonToolbox, timeGranularities, timeGranularityAxisPointerLabelFormatter, timeGranularityAxisType } from '@/shared/echarts';
import { titleTemplate } from '@/shared';
import type { Writable } from '@/shared';
import _ from 'lodash';
import { ref } from 'vue';
Expand Down
6 changes: 4 additions & 2 deletions fe/src/views/Status.vue
Expand Up @@ -7,14 +7,16 @@
<span class="input-group-text"><FontAwesomeIcon icon="calendar-alt" /></span>
<TimeRange v-model:startTime="query.startTime"
v-model:endTime="query.endTime"
:timesAgo="{ day: 1 }" />
id="queryTimeRange" :timesAgo="{ day: 1 }" />
</div>
</div>
<label class="col-1 col-form-label text-end" for="queryTimeGranularity">时间粒度</label>
<div class="col-2">
<div class="input-group">
<span class="input-group-text"><FontAwesomeIcon icon="clock" /></span>
<TimeGranularity v-model="query.timeGranularity" :granularities="['minute', 'hour', 'day']" />
<TimeGranularity v-model="query.timeGranularity"
id="queryTimeGranularity"
:granularities="['minute', 'hour', 'day']" />
</div>
</div>
</div>
Expand Down
2 changes: 1 addition & 1 deletion fe/vite.config.ts
Expand Up @@ -4,7 +4,7 @@ import vue from '@vitejs/plugin-vue';

// https://vitejs.dev/config/
export default defineConfig({
plugins: [vue()],
plugins: [vue({ script: { defineModel: true } })],
build: { target: 'esnext' },
resolve: {
alias: [
Expand Down

0 comments on commit 1403ed2

Please sign in to comment.