chore: 基线提交(重构前代码快照)

- git 初始化 + .gitignore 补全(根 .env / logs / instance / __pycache__ 等)
- 修复 utils/.gitignore 误将整个 utils/ 源码层忽略的问题,补入全部工具源码(含 ip2region.xdb)
- 含后端全部代码:application / extensions / utils / config / migrations
- 含前端 ui/(后续整体迁走)
- 不含根 .env(含密钥,本地保留)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
DjangoAdmin Dev
2026-08-07 12:12:06 +08:00
co-authored by Claude
commit 15f2a5e097
591 changed files with 95894 additions and 0 deletions
+1
View File
@@ -0,0 +1 @@
export { default as BasicSelect } from './src/BasicSelect.vue';
@@ -0,0 +1,115 @@
<template>
<el-select v-bind="getBindValues" v-model="selectValue" @change="change">
<el-option v-for="item in options" :key="item.value" :label="item.label" :value="item.value" />
<template v-for="item in Object.keys($slots)" :key="item" #[item]="data">
<slot v-bind="data" :name="item"></slot>
</template>
</el-select>
</template>
<script lang="ts" setup>
import { ref, unref, computed, onMounted, watch } from 'vue';
import { basicProps } from './props';
import { createStorage } from '@/utils/Storage';
const Storage = createStorage({ storage: localStorage });
const props = defineProps({ ...basicProps });
const emit = defineEmits(['update:modelValue']);
const selectValue = ref(props.modelValue);
const loading = ref(true);
const options = ref<any[]>([]);
const getProps = computed(() => {
return { ...props };
});
watch(
() => props.modelValue,
() => {
selectValue.value = props.modelValue;
},
{
immediate: true,
deep: true,
},
);
const selectWidth = props.block ? '100%' : `${props.width}px`;
const getBindValues = computed(() => {
return {
...unref(getProps),
clearable: true,
loading: loading.value,
style: { width: selectWidth },
};
});
const getCacheData = computed(() => {
return props.cacheKey ? Storage.get(props.cacheKey) : null;
});
//选中值发生变化时触发
function change(value) {
emit('update:modelValue', value);
}
//初始化
function init() {
const { cache, cacheKey } = props;
//判断是否启用缓存
if (cache && cacheKey && getCacheData.value) {
options.value = getCacheData.value || [];
loading.value = false;
return;
}
//获取新数据
fetch();
}
//触发取新数据
async function fetch() {
loading.value = true;
const { request, cacheKey, cache } = props;
if (!request) {
if (props.options && props.options.length) {
options.value = props.options;
loading.value = false;
if (cache && cacheKey) Storage.set(cacheKey, props.options);
}
return;
}
try {
const res = await request();
options.value = res || [];
loading.value = false;
if (cache && cacheKey && res && res.length) Storage.set(cacheKey, res);
} catch (error) {
console.error(error);
}
}
//获取数据源
function getData() {
const { cache, cacheKey } = props;
return cache && cacheKey ? Storage.get(props.cacheKey) : options.value;
}
//获取缓存
onMounted(() => {
init();
});
//暴露方法
defineExpose({
fetch,
getData,
});
</script>
<style lang="scss" scoped></style>
+37
View File
@@ -0,0 +1,37 @@
import type { PropType } from 'vue';
import { SelectProps } from 'element-plus/es/components/select-v2/src/defaults';
export const basicProps = {
...SelectProps,
modelValue: {
type: [String, Number, Boolean, Object],
},
request: {
type: Function as PropType<(...arg: any[]) => Promise<any>>,
default: null,
required: true,
},
options: {
type: Array,
default: [],
},
//是否缓存数据
cache: {
type: Boolean,
default: false,
},
//开启缓存,必传缓存key,否则不生效
cacheKey: {
type: String,
default: '',
},
width: {
type: Number as PropType<number>,
default: 150,
},
//block属性将使按钮适合其父宽度
block: {
type: Boolean,
default: false,
},
};