Browse Source

导入失败下载校验文件

master
wanggang 1 year ago
parent
commit
14120ffd49
  1. 17
      code/src/Modules/SettleAccount/host/SettleAccount.HttpApi.Host/wwwroot/api/user.js
  2. 8
      code/src/Modules/SettleAccount/host/SettleAccount.HttpApi.Host/wwwroot/assets/demo/index.html
  3. 1987
      code/src/Modules/SettleAccount/host/SettleAccount.HttpApi.Host/wwwroot/assets/demo/lib/pinia.esm-browser.js
  4. 3613
      code/src/Modules/SettleAccount/host/SettleAccount.HttpApi.Host/wwwroot/assets/demo/lib/vue-router.esm-browser.js
  5. 15377
      code/src/Modules/SettleAccount/host/SettleAccount.HttpApi.Host/wwwroot/assets/demo/lib/vue.esm-browser.js
  6. 6
      code/src/Modules/SettleAccount/host/SettleAccount.HttpApi.Host/wwwroot/assets/demo/pages/component.html
  7. 115
      code/src/Modules/SettleAccount/host/SettleAccount.HttpApi.Host/wwwroot/components/form/form-input.js
  8. 2
      code/src/Modules/SettleAccount/host/SettleAccount.HttpApi.Host/wwwroot/components/form/form-item.js
  9. 125
      code/src/Modules/SettleAccount/host/SettleAccount.HttpApi.Host/wwwroot/components/list/index.js
  10. 4
      code/src/Modules/SettleAccount/host/SettleAccount.HttpApi.Host/wwwroot/index.html
  11. 3
      code/src/Modules/SettleAccount/host/SettleAccount.HttpApi.Host/wwwroot/models/tb_re-parts-relationship_service.js
  12. 14
      code/src/Modules/SettleAccount/host/SettleAccount.HttpApi.Host/wwwroot/request/index.js
  13. 4
      code/src/Modules/SettleAccount/host/SettleAccount.HttpApi.Host/wwwroot/utils/validation.js
  14. 6
      code/src/Modules/SettleAccount/host/SettleAccount.HttpApi.Host/wwwroot/views/login.js
  15. 19
      code/src/Modules/SettleAccount/src/SettleAccount.Application/Entities/BQ/VmiAppService.cs

17
code/src/Modules/SettleAccount/host/SettleAccount.HttpApi.Host/wwwroot/api/user.js

@ -22,21 +22,6 @@ const isLogin = async () => {
return false;
};
const login = async (data) => {
const url = "connect-token";
const appStore = useAppStore();
const result = await post(url, data, { headers: { "Content-Type": "application/x-www-form-urlencoded" } }, true);
if (!result.errors) {
appStore.token = result.data.access_token;
setRefreshToken(result.data.refresh_token);
appStore.user = await getUser();
await refreshRouter();
const redirect = router.currentRoute.value.query?.redirect ?? "/";
router.push(redirect);
}
return result;
};
const logout = () => {
const appStore = useAppStore();
appStore.token = null;
@ -87,4 +72,4 @@ const removeRefreshToken = () => {
connection.stop();
};
export { isLogin, login, logout, getAccessToken, setAccessToken, setRefreshToken, getUser, hasPermission };
export { isLogin, logout, getAccessToken, setAccessToken, setRefreshToken, getUser, hasPermission };

8
code/src/Modules/SettleAccount/host/SettleAccount.HttpApi.Host/wwwroot/assets/demo/index.html

@ -46,9 +46,9 @@
<script type="importmap">
{
"imports": {
"vue": "./lib/vue.esm-browser.js",
"vue-router": "./lib/vue-router.esm-browser.js",
"pinia": "./lib/pinia.esm-browser.js"
"vue": "/lib/vue/vue.esm-browser.js",
"vue-router": "/lib/vue-router/vue-router.esm-browser.js",
"pinia": "/lib/pinia/pinia.esm-browser.js"
}
}
</script>
@ -82,4 +82,4 @@
</script>
</body>
</html>
</html>

1987
code/src/Modules/SettleAccount/host/SettleAccount.HttpApi.Host/wwwroot/assets/demo/lib/pinia.esm-browser.js

File diff suppressed because it is too large

3613
code/src/Modules/SettleAccount/host/SettleAccount.HttpApi.Host/wwwroot/assets/demo/lib/vue-router.esm-browser.js

File diff suppressed because it is too large

15377
code/src/Modules/SettleAccount/host/SettleAccount.HttpApi.Host/wwwroot/assets/demo/lib/vue.esm-browser.js

File diff suppressed because it is too large

6
code/src/Modules/SettleAccount/host/SettleAccount.HttpApi.Host/wwwroot/assets/demo/pages/component.html

@ -13,9 +13,9 @@
<script type="importmap">
{
"imports": {
"vue": "../lib/vue.esm-browser.js",
"vue-router": "../lib/vue-router.esm-browser.js",
"pinia": "../lib/pinia.esm-browser.js"
"vue": "/lib/vue/vue.esm-browser.js",
"vue-router": "/lib/vue-router/vue-router.esm-browser.js",
"pinia": "/lib/pinia/pinia.esm-browser.js"
}
}
</script>

115
code/src/Modules/SettleAccount/host/SettleAccount.HttpApi.Host/wwwroot/components/form/form-input.js

@ -1,8 +1,9 @@
import html from "html";
import { ref, reactive, watch, onMounted } from "vue";
import { ref, reactive, watch, onMounted, nextTick } from "vue";
import { dayjs } from "element-plus";
import request from "../../request/index.js";
import { importFunction } from "../../utils/index.js";
import { importFunction, bytesFormat } from "../../utils/index.js";
import { ElMessage, useFormItem } from "element-plus";
export default {
template: html`
@ -32,20 +33,12 @@ export default {
<template v-else-if="getInput(schema)==='month'">
<el-date-picker v-model="model[prop]" :type="schema.input" :value-format="schema.format" />
</template>
<el-input
:disabled="getDisabled()"
:placeholder="schema.title"
v-model="model[prop]"
type="number"
v-else-if="getInput(schema)==='number'"
/>
<el-input-number
:disabled="getDisabled()"
:placeholder="schema.title"
v-model="model[prop]"
:precision="0"
v-else-if="getInput(schema)==='integer'"
/>
<template v-else-if="getInput(schema)==='number'">
<el-input :disabled="getDisabled()" :placeholder="schema.title" v-model="model[prop]" type="number" />
</template>
<template v-else-if="getInput(schema)==='integer'">
<el-input-number :disabled="getDisabled()" :placeholder="schema.title" v-model="model[prop]" :precision="0" />
</template>
<template v-else-if="getInput(schema)==='boolean'">
<el-select :disabled="getDisabled()" v-model="model[prop]" :placeholder="schema.title" v-if="schema.nullable">
<el-option prop="select" value="" :label="$t('select')" />
@ -54,23 +47,41 @@ export default {
</el-select>
<el-switch v-model="model[prop]" type="checked" v-else />
</template>
<template v-else-if="getInput(schema)==='file'">
<el-upload
ref="uploadRef"
v-model:file-list="model[prop]"
class="upload"
drag
:accept="schema.accept"
:multiple="schema.multiple"
:limit="limit"
:auto-upload="false"
:on-change="handleChange"
>
<template #trigger>
<el-icon style="font-size:4em;">
<ep-upload-filled />
</el-icon>
</template>
<template #tip>
<div class="el-upload__tip">
<div>
单个文件大小限制{{ bytesFormat(size) }}上传数量限制{{ limit }}
<template v-if="schema.accept">上传文件类型{{ schema.accept }}</template>
</div>
</div>
</template>
</el-upload>
</template>
<template v-else>
<el-input
:clearable="!!schema.clearable"
:disabled="getDisabled()"
:placeholder="schema.title"
v-model="model[prop]"
type="password"
show-password
v-if="schema.input==='password'"
/>
<el-input
:clearable="!!schema.clearable"
:disabled="getDisabled()"
:placeholder="schema.title"
v-model="model[prop]"
:type="schema.input??'text'"
v-else
:show-password="schema.input==='password'"
/>
</template>
</template>
@ -96,12 +107,57 @@ export default {
return schema.input ?? schema.type;
};
/*end*/
//options
const selectProps = ref({});
const selectValues = ref([]);
const options = ref([]);
//watch
//upload
const fileList = ref([]);
const limit = props.schema.multiple ? props.schema.limit ?? 5 : 1;
const size = props.schema.size ?? 1024 * 1024;
const fileTypes = props.schema.accept?.split(",").map((o) => o.toLowerCase()) ?? [];
// const beforeUpload = (file) => {
// if (props.schema.accept && !fileTypes.some((o) => o === file.type)) {
// ElMessage.error(
// `当前文件类型 ${mimetypeToExension(file.type) ?? file.type},可选文件类型 ${props.schema.accept}`
// );
// return false;
// }
// if (file.size > size.value) {
// ElMessage.error(`当前文件大小 ${formatBytes(file.size)},已超过 ${formatBytes(size.value)}`);
// return false;
// }
// return true;
// };
const { formItem } = useFormItem();
const handleChange = async (uploadFile, uploadFiles) => {
const ext = uploadFile.name.substr(uploadFile.name.lastIndexOf("."));
const index = uploadFiles.findIndex((o) => o.uid !== uploadFile.uid);
if (props.schema.accept && !fileTypes.some((o) => o === ext)) {
ElMessage.error(`当前文件 ${uploadFile.name} 不是可选文件类型 ${props.schema.accept}`);
uploadFiles.splice(index, 1);
return false;
}
if (uploadFile.size > size) {
ElMessage.error(`当前文件大小 ${bytesFormat(uploadFile.size)} 已超过 ${bytesFormat(size)}`);
uploadFiles.splice(index, 1);
return false;
}
if (uploadFiles.length) {
model[props.prop] = props.schema.multiple ? uploadFiles : uploadFiles[0];
} else {
model[props.prop] = props.schema.multiple ? [] : null;
}
try {
await formItem.validate();
} catch (error) {
console.log(error);
}
};
//watch
watch(
() => model[props.prop],
async (value) => {
@ -143,6 +199,11 @@ export default {
selectProps,
selectValues,
options,
bytesFormat,
fileList,
limit,
size,
handleChange,
};
},
};

2
code/src/Modules/SettleAccount/host/SettleAccount.HttpApi.Host/wwwroot/components/form/form-item.js

@ -10,7 +10,7 @@ export default {
template: html`
<template v-if="!schema.hidden">
<template v-if="schema.type==='object'"></template>
<template v-else-if="schema.type!=='array'||schema.items.type!=='array'">
<template v-else-if="schema.type!=='array'||schema.items?.type!=='array'">
<el-form-item
:title="prop"
:label="schema.title"

125
code/src/Modules/SettleAccount/host/SettleAccount.HttpApi.Host/wwwroot/components/list/index.js

@ -263,25 +263,15 @@ export default {
</template>
<template v-else-if="editFormMode==='import'">
<app-form
mode="import"
ref="importFormRef"
mode="update"
label-position="left"
:schema="config.import?.schema"
v-model="importModel"
:hideButton="true"
:isQueryForm="true"
style="height:100%;"
>
<el-form-item :label="$t('文件')" label-width="80px">
<el-upload
ref="uploadRef"
class="upload"
drag
accept=".xlsx"
:auto-upload="false"
:on-change="handleChange"
>
<el-icon class="el-icon--upload"><ep-upload-filled /></el-icon>
</el-upload>
</el-form-item>
</app-form>
</template>
<template v-else-if="editFormMode==='filter'">
@ -408,6 +398,7 @@ export default {
const tableSchema = ref({});
const tableData = ref([]);
const editFormRef = ref(null);
const importFormRef = ref(null);
const editFormloading = ref(false);
const editFormMode = ref(null);
const editFormTitle = ref("");
@ -424,11 +415,26 @@ export default {
businessType: route.meta.businessType,
};
const exportModel = ref(defaultExportModel);
const defaultImportModel = config.import?.schema ? schemaToModel(config.import.schema) : {};
const importModel = ref(defaultImportModel);
const factories = ref([]);
//
config.import ??= { schema: { type: "object", properties: {} } };
config.import.schema.properties.files ??= {
title: "文件",
type: "array",
multiple: true,
input: "file",
accept: ".xlsx",
default: [],
limit: 3,
rules: [
{
required: true,
trigger: "change",
},
],
};
const defaultImportModel = schemaToModel(config.import.schema);
const importModel = ref(null);
const versions = ref([]);
const fileList = ref([]);
const getSortModel = (model) => {
(model.sorting ?? "")
.split(",")
@ -575,10 +581,6 @@ export default {
}
}
}
// await post(
// url,
// rows.map((o) => o.id)
// );
await load();
} else if (item.path === "export") {
//export
@ -609,20 +611,7 @@ export default {
importModel.value = Object.assign({}, defaultImportModel);
editFormloading.value = true;
editFormTitle.value = `${t(item.path)}${config.query.schema.title}`;
fileList.value = [];
dialogVisible.value = true;
// versions.value = (
// await request("settleaccount/centralized-control/get-all", null, { method: "POST" })
// ).data.items.map((o) => ({
// value: o.version,
// label: o.version,
// }));
// factories.value = (
// await request("settleaccount/code-setting/get-all", null, { method: "POST" })
// ).data.items.map((o) => ({
// value: o.project,
// label: o.project,
// }));
} catch (e) {
console.log(e);
} finally {
@ -667,38 +656,47 @@ export default {
dialogVisible.value = false;
editFormMode.value = null;
} else if (editFormMode.value === "compare") {
// const postData = JSON.parse(JSON.stringify(queryModel.value));
// postData.filters = filterList.value.filter((o) => o.property && o.value);
// delete postData.query["items"];
// delete postData.query["id"];
// const url = `${baseUrl}/${editFormMode.value}?${qs.stringify(exportModel)}`;
// const response = await post(url, postData);
// download(response);
const url = config.edit.compareUrl;
await request(url, exportModel.value, { method: config.edit.compareMethod });
dialogVisible.value = false;
} else if (editFormMode.value === "import") {
editFormloading.value = true;
const url = config.edit.importUrl;
const formData = new FormData();
// formData.append("version", importModel.value.version);
// // formData.append("factory", importModel.value.factory);
// Object.keys(importModel.value).forEach((q) => {if(importModel.value)
Object.keys(importModel.value).forEach((q) => {
if (importModel.value[q]) {
formData.append(q, importModel.value[q]);
try {
const valid = await importFormRef.value.validate();
if (valid) {
editFormloading.value = true;
const url = config.edit.importUrl;
const formData = new FormData();
//
if (config.query.schema.properties.businessType?.default) {
formData.append("businessType", config.query.schema.properties.businessType.default);
}
Object.keys(importModel.value).forEach((propertyName) => {
if (importModel.value[propertyName]) {
const schema = config.import.schema.properties[propertyName];
const value = importModel.value[propertyName];
if (schema?.type === "array") {
importModel.value[propertyName].forEach((item) => {
formData.append(propertyName, schema.input === "file" ? item.raw : item);
});
} else {
formData.append(propertyName, schema.input === "file" ? value.raw : value);
}
}
});
const result = await request(url, formData);
if (result.data?.code === 200) {
editFormloading.value = false;
dialogVisible.value = false;
await load();
} else if (result.data?.code === 400 && result.data.fileName) {
window.open(getUrl(`settleaccount/getblobfile/download/${result.data.fileName}`));
}
}
});
if (config.query.schema.properties.businessType?.default) {
formData.append("businessType", config.query.schema.properties.businessType.default);
}
for (let i = 0; i < fileList.value.length; i++) {
formData.append(`files`, fileList.value[i].raw);
} catch (error) {
console.log(error);
} finally {
editFormloading.value = false;
}
await post(url, formData);
editFormloading.value = false;
dialogVisible.value = false;
await load();
} else if (editFormMode.value === "filter") {
await load();
dialogVisible.value = false;
@ -728,9 +726,6 @@ export default {
const response = await get(url);
download(url, response.filename);
};
const handleChange = (uploadFile, uploadFiles) => {
fileList.value = uploadFiles;
};
const getButtonDisabled = async (src, row) => {
if (src) {
const method = await importFunction(src);
@ -886,6 +881,7 @@ export default {
sortChange,
getProp,
getImportTemplate,
importFormRef,
editFormRef,
editFormloading,
editFormMode,
@ -902,10 +898,7 @@ export default {
submit,
showList,
subListQuery,
fileList,
handleChange,
getButtonDisabled,
factories,
versions,
pushfilterList,
getOperators,

4
code/src/Modules/SettleAccount/host/SettleAccount.HttpApi.Host/wwwroot/index.html

@ -49,7 +49,7 @@
"html":"./utils/index.js",
"detect-it":"./lib/detect-it/detect-it.esm.js",
"lodash":"./lib/lodash/lodash.esm.js",
"vue": "./lib/vue/vue.esm-browser.prod.js",
"vue": "./lib/vue/vue.esm-browser.js",
"vue-router": "./lib/vue-router/vue-router.esm-browser.js",
"vue-i18n":"./lib/vue-i18n/vue-i18n.esm-browser.prod.js",
"pinia": "./lib/pinia/pinia.esm-browser.js",
@ -77,4 +77,4 @@
<script type="module" src="./main.js"></script>
</body>
</html>
</html>

3
code/src/Modules/SettleAccount/host/SettleAccount.HttpApi.Host/wwwroot/models/tb_re-parts-relationship_service.js

@ -84,9 +84,6 @@ export default function () {
},
table: {
schema: schema,
},
import:{
},
edit: {
importUrl,

14
code/src/Modules/SettleAccount/host/SettleAccount.HttpApi.Host/wwwroot/request/index.js

@ -60,13 +60,15 @@ const getResult = async (response) => {
result.filename = getFileName(response.headers.get("Content-Disposition"));
}
} else {
result.errors = await response.json();
if (result.errors) {
ElMessageBox.alert(
`错误:${result.errors?.error?.message ?? messages.get(response.status)}`,
`代码:${result.errors?.error?.code}`
);
try {
result.errors = await response.json();
} catch (error) {
console.log(error);
}
ElMessageBox.alert(
`${result.errors?.error?.message ?? messages.get(response.status) ?? result.status}`,
`${result.errors?.error?.code ?? result.status}`
);
}
return result;
};

4
code/src/Modules/SettleAccount/host/SettleAccount.HttpApi.Host/wwwroot/utils/validation.js

@ -129,7 +129,9 @@ const getRules = (parentSchema, property, data) => {
rule.type = property.type;
}
if (rule.validator) {
rule.validator = validators[rule.validator];
if (rule.validator.constructor === String) {
rule.validator = validators[rule.validator];
}
}
if (!rule.message) {
if (rule.required) {

6
code/src/Modules/SettleAccount/host/SettleAccount.HttpApi.Host/wwwroot/views/login.js

@ -1,9 +1,9 @@
import html, { schemaToModel } from "html";
import { ref, reactive } from "vue";
import { reactive } from "vue";
import AppForm from "../components/form/index.js";
import { login, setRefreshToken, getUser, setAccessToken } from "../api/user.js";
import { getUser, setAccessToken } from "../api/user.js";
import router, { refreshRouter } from "../router/index.js";
import request, { post } from "../request/index.js";
import request from "../request/index.js";
import LayoutLogo from "../layouts/logo.js";
import LayoutLocale from "../layouts/locale.js";
import LayoutFooter from "../layouts/footer.js";

19
code/src/Modules/SettleAccount/src/SettleAccount.Application/Entities/BQ/VmiAppService.cs

@ -55,6 +55,7 @@ public interface IVmiService : IApplicationService, ITransientDependency, IJobSe
public class VmiAppService : ApplicationService, IVmiService, IJobService, ITransientDependency
{
private readonly IConfiguration _cfg;
private readonly IServiceProvider _serviceProvider;
private readonly INormalEfCoreRepository<VmiBalance, Guid> _balanceRepository;
private readonly INormalEfCoreRepository<VmiLog, Guid> _logRepository;
private readonly INormalEfCoreRepository<VmiSnapshot, Guid> _snapshotRepository;
@ -63,6 +64,7 @@ public class VmiAppService : ApplicationService, IVmiService, IJobService, ITran
private readonly ICurrentUser _currentUser;
public VmiAppService(IConfiguration cfg,
IServiceProvider serviceProvider,
INormalEfCoreRepository<VmiBalance, Guid> balanceRepository,
INormalEfCoreRepository<VmiLog, Guid> logRepository,
INormalEfCoreRepository<VmiSnapshot, Guid> snapshotRepository,
@ -71,6 +73,7 @@ public class VmiAppService : ApplicationService, IVmiService, IJobService, ITran
ICurrentUser currentUser)
{
this._cfg = cfg;
this._serviceProvider = serviceProvider;
this._balanceRepository = balanceRepository;
this._logRepository = logRepository;
this._snapshotRepository = snapshotRepository;
@ -124,7 +127,7 @@ public class VmiAppService : ApplicationService, IVmiService, IJobService, ITran
/// <summary>
/// 定时备份:0 0 8 26 * ?
/// </summary>
[HttpPost]
[NonAction]
[DisableValidation]
public virtual Task Invoke(IServiceProvider serviceProvider)
{
@ -170,6 +173,20 @@ public class VmiAppService : ApplicationService, IVmiService, IJobService, ITran
return Task.CompletedTask;
}
/// <summary>
/// 定时备份:0 0 8 26 * ?
/// </summary>
[HttpPost("invoke")]
[DisableValidation]
public virtual Task VmiBackup()
{
Task.Run(async () =>
{
await Invoke(_serviceProvider).ConfigureAwait(false);
});
return Task.CompletedTask;
}
/// <summary>
/// 发运入库\反结入库\调整入库
/// </summary>

Loading…
Cancel
Save