Merge branch 'master' of https://dev.azure.com/alicorn-dev/KintoneAppBuilder/_git/KintoneAppBuilder
This commit is contained in:
2
backend/.gitignore
vendored
2
backend/.gitignore
vendored
@@ -124,3 +124,5 @@ cython_debug/
|
|||||||
|
|
||||||
# VS Code settings
|
# VS Code settings
|
||||||
.vscode/
|
.vscode/
|
||||||
|
|
||||||
|
*.lock
|
||||||
@@ -2,21 +2,150 @@ from fastapi import APIRouter, UploadFile,HTTPException,File
|
|||||||
from io import BytesIO
|
from io import BytesIO
|
||||||
import typing as t
|
import typing as t
|
||||||
import pandas as pd
|
import pandas as pd
|
||||||
|
import json
|
||||||
|
import httpx
|
||||||
|
import app.core.config as c
|
||||||
|
|
||||||
kinton_router = r = APIRouter()
|
kinton_router = r = APIRouter()
|
||||||
|
|
||||||
|
|
||||||
@r.post("/upload",)
|
@r.post("/upload",)
|
||||||
async def upload(file:UploadFile = File(...)):
|
async def upload(files:t.List[UploadFile] = File(...)):
|
||||||
dataframes = []
|
dataframes = []
|
||||||
if file.filename.endswith('.xlsx'):
|
for file in files:
|
||||||
try:
|
if file.filename.endswith('.xlsx'):
|
||||||
content = await file.read()
|
try:
|
||||||
df = pd.read_excel(BytesIO(content))
|
content = await file.read()
|
||||||
dataframes.append(df)
|
df = pd.read_excel(BytesIO(content))
|
||||||
except Exception as e:
|
print(df)
|
||||||
raise HTTPException(status_code=400, detail=f"Error occurred while parsing file {file.filename}: {str(e)}")
|
dataframes.append(df)
|
||||||
else:
|
except Exception as e:
|
||||||
raise HTTPException(status_code=400, detail=f"File {file.filename} is not an Excel file")
|
raise HTTPException(status_code=400, detail=f"Error occurred while parsing file {file.filename}: {str(e)}")
|
||||||
return {"file": file.filename}
|
else:
|
||||||
|
raise HTTPException(status_code=400, detail=f"File {file.filename} is not an Excel file")
|
||||||
|
|
||||||
|
return {"files": [file.filename for file in files]}
|
||||||
|
|
||||||
|
@r.get("/allapps",)
|
||||||
|
async def allapps():
|
||||||
|
headers={c.API_V1_AUTH_KEY:c.API_V1_AUTH_VALUE}
|
||||||
|
url = f"{c.BASE_URL}{c.API_V1_STR}/apps.json"
|
||||||
|
r = httpx.get(url,headers=headers)
|
||||||
|
return r.json()
|
||||||
|
|
||||||
|
|
||||||
|
@r.post("/createapp",)
|
||||||
|
async def createapp(name:str):
|
||||||
|
headers={c.API_V1_AUTH_KEY:c.API_V1_AUTH_VALUE,"Content-Type": "application/json"}
|
||||||
|
data = {"name":name}
|
||||||
|
url = f"{c.BASE_URL}{c.API_V1_STR}/preview/app.json"
|
||||||
|
r = httpx.post(url,headers=headers,data=json.dumps(data))
|
||||||
|
result = r.json()
|
||||||
|
if result.get("app") != None:
|
||||||
|
url = f"{c.BASE_URL}{c.API_V1_STR}/preview/app/deploy.json"
|
||||||
|
data = {"apps":[result],"revert": False}
|
||||||
|
r = httpx.post(url,headers=headers,data=json.dumps(data))
|
||||||
|
return r.json
|
||||||
|
|
||||||
|
property=["label","code","type","required","defaultValue","options"]
|
||||||
|
|
||||||
|
@r.post("/createappfromexcel",)
|
||||||
|
async def createappfromexcel(files:t.List[UploadFile] = File(...)):
|
||||||
|
for file in files:
|
||||||
|
if file.filename.endswith('.xlsx'):
|
||||||
|
try:
|
||||||
|
content = await file.read()
|
||||||
|
#アプリ名
|
||||||
|
df = pd.read_excel(BytesIO(content))
|
||||||
|
# print(df)
|
||||||
|
appname = df.iloc[0,2]
|
||||||
|
col=[]
|
||||||
|
for row in range(5,len(df)):
|
||||||
|
if not df.iloc[row,3] in c.KINTONE_FIELD_TYPE:
|
||||||
|
continue
|
||||||
|
p=[]
|
||||||
|
for column in range(1,7):
|
||||||
|
if(not pd.isna(df.iloc[row,column])):
|
||||||
|
if(property[column-1]=="options"):
|
||||||
|
o=[]
|
||||||
|
for v in df.iloc[row,column].split(','):
|
||||||
|
o.append(f"\"{v.split('|')[0]}\":{{\"label\":\"{v.split('|')[0]}\",\"index\":\"{v.split('|')[1]}\"}}")
|
||||||
|
p.append(f"\"{property[column-1]}\":{{{','.join(o)}}}")
|
||||||
|
elif(property[column-1]=="required"):
|
||||||
|
p.append(f"\"{property[column-1]}\":{df.iloc[row,column]}")
|
||||||
|
else:
|
||||||
|
p.append(f"\"{property[column-1]}\":\"{df.iloc[row,column]}\"")
|
||||||
|
col.append(f"\"{df.iloc[row,2]}\":{{{','.join(p)}}}")
|
||||||
|
|
||||||
|
headers={c.API_V1_AUTH_KEY:c.API_V1_AUTH_VALUE,"Content-Type": "application/json"}
|
||||||
|
data = {"name":appname}
|
||||||
|
url = f"{c.BASE_URL}{c.API_V1_STR}/preview/app.json"
|
||||||
|
r = httpx.post(url,headers=headers,data=json.dumps(data))
|
||||||
|
result1 = r.json()
|
||||||
|
if result1.get("app") != None:
|
||||||
|
url = f"{c.BASE_URL}{c.API_V1_STR}/preview/app/form/fields.json"
|
||||||
|
form = f"{{\"app\":{result1['app']},\"properties\":{{{','.join(col)}}}}}".replace("False","false").replace("True","true")
|
||||||
|
print(form)
|
||||||
|
data = json.loads(form)
|
||||||
|
r = httpx.post(url,headers=headers,data=json.dumps(data))
|
||||||
|
result2 = r.json()
|
||||||
|
if result2.get("revision") != None:
|
||||||
|
url = f"{c.BASE_URL}{c.API_V1_STR}/preview/app/deploy.json"
|
||||||
|
data = {"apps":[{"app":result1["app"],"revision":result2["revision"]}],"revert": False}
|
||||||
|
r = httpx.post(url,headers=headers,data=json.dumps(data))
|
||||||
|
except Exception as e:
|
||||||
|
raise HTTPException(status_code=400, detail=f"Error occurred while parsing file {file.filename}: {str(e)}")
|
||||||
|
else:
|
||||||
|
raise HTTPException(status_code=400, detail=f"File {file.filename} is not an Excel file")
|
||||||
|
|
||||||
|
return {"app":result1["app"],"revision":result2["revision"]}
|
||||||
|
|
||||||
|
|
||||||
|
@r.post("/updateappfromexcel",)
|
||||||
|
async def updateappfromexcel(app:str,revision:str,files:t.List[UploadFile] = File(...)):
|
||||||
|
for file in files:
|
||||||
|
if file.filename.endswith('.xlsx'):
|
||||||
|
try:
|
||||||
|
content = await file.read()
|
||||||
|
#アプリ名
|
||||||
|
df = pd.read_excel(BytesIO(content))
|
||||||
|
# print(df)
|
||||||
|
appname = df.iloc[0,2]
|
||||||
|
col=[]
|
||||||
|
for row in range(5,len(df)):
|
||||||
|
if not df.iloc[row,3] in c.KINTONE_FIELD_TYPE:
|
||||||
|
continue
|
||||||
|
p=[]
|
||||||
|
for column in range(1,7):
|
||||||
|
if(not pd.isna(df.iloc[row,column])):
|
||||||
|
if(property[column-1]=="options"):
|
||||||
|
o=[]
|
||||||
|
for v in df.iloc[row,column].split(','):
|
||||||
|
o.append(f"\"{v.split('|')[0]}\":{{\"label\":\"{v.split('|')[0]}\",\"index\":\"{v.split('|')[1]}\"}}")
|
||||||
|
p.append(f"\"{property[column-1]}\":{{{','.join(o)}}}")
|
||||||
|
elif(property[column-1]=="required"):
|
||||||
|
p.append(f"\"{property[column-1]}\":{df.iloc[row,column]}")
|
||||||
|
else:
|
||||||
|
p.append(f"\"{property[column-1]}\":\"{df.iloc[row,column]}\"")
|
||||||
|
col.append(f"\"{df.iloc[row,2]}\":{{{','.join(p)}}}")
|
||||||
|
|
||||||
|
headers={c.API_V1_AUTH_KEY:c.API_V1_AUTH_VALUE,"Content-Type": "application/json"}
|
||||||
|
|
||||||
|
url = f"{c.BASE_URL}{c.API_V1_STR}/preview/app/form/fields.json"
|
||||||
|
form = f"{{\"app\":{app},\"revision\": {revision},\"properties\":{{{','.join(col)}}}}}".replace("False","false").replace("True","true")
|
||||||
|
print(form)
|
||||||
|
data = json.loads(form)
|
||||||
|
r = httpx.put(url,headers=headers,data=json.dumps(data))
|
||||||
|
result = r.json()
|
||||||
|
if result.get("revision") != None:
|
||||||
|
url = f"{c.BASE_URL}{c.API_V1_STR}/preview/app/deploy.json"
|
||||||
|
data = {"apps":[{"app":app,"revision":result["revision"]}],"revert": False}
|
||||||
|
r = httpx.post(url,headers=headers,data=json.dumps(data))
|
||||||
|
except Exception as e:
|
||||||
|
raise HTTPException(status_code=400, detail=f"Error occurred while parsing file {file.filename}: {str(e)}")
|
||||||
|
else:
|
||||||
|
raise HTTPException(status_code=400, detail=f"File {file.filename} is not an Excel file")
|
||||||
|
|
||||||
|
return r.json()
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -4,4 +4,12 @@ PROJECT_NAME = "KintoneAppBuilder"
|
|||||||
|
|
||||||
SQLALCHEMY_DATABASE_URI = os.getenv("DATABASE_URL")
|
SQLALCHEMY_DATABASE_URI = os.getenv("DATABASE_URL")
|
||||||
|
|
||||||
API_V1_STR = "/api/v1"
|
BASE_URL = "https://mfu07rkgnb7c.cybozu.com"
|
||||||
|
|
||||||
|
API_V1_STR = "/k/v1"
|
||||||
|
|
||||||
|
API_V1_AUTH_KEY = "X-Cybozu-Authorization"
|
||||||
|
|
||||||
|
API_V1_AUTH_VALUE = "TVhaOm1heHoxMjA1"
|
||||||
|
|
||||||
|
KINTONE_FIELD_TYPE=["GROUP","GROUP_SELECT","CHECK_BOX","SUBTABLE","RICH_TEXT","RICH_TEXT","LINK","REFERENCE_TABLE","CALC","TIME","NUMBER","ORGANIZATION_SELECT","FILE","DATETIME","DATE","MULTI_SELECT","SINGLE_LINE_TEXT","MULTI_LINE_TEXT"]
|
||||||
|
|||||||
3684
frontend/package-lock.json
generated
3684
frontend/package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@@ -1,18 +1,20 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="q-pa-md">
|
<div class="q-pa-md">
|
||||||
<q-uploader
|
<q-uploader
|
||||||
|
:on-finish="uploadFinished"
|
||||||
style="max-width: 400px"
|
style="max-width: 400px"
|
||||||
:url="uploadUrl"
|
:url="uploadUrl"
|
||||||
:label="title"
|
:label="title"
|
||||||
accept=".csv,.xlsx"
|
accept=".csv,.xlsx"
|
||||||
v-on:rejected="onRejected"
|
v-on:rejected="onRejected"
|
||||||
v-on:finish="onUploadFinish"
|
v-on:finish="uploadFinished"
|
||||||
field-name="file"
|
field-name="file"
|
||||||
></q-uploader>
|
></q-uploader>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
</template>
|
</template>
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { useQuasar } from 'quasar';
|
import { createUploaderComponent, useQuasar } from 'quasar';
|
||||||
|
|
||||||
|
|
||||||
const $q=useQuasar();
|
const $q=useQuasar();
|
||||||
@@ -36,27 +38,25 @@
|
|||||||
$q.notify({
|
$q.notify({
|
||||||
type: 'negative',
|
type: 'negative',
|
||||||
message: `CSVおよびExcelファイルを選択してください。`
|
message: `CSVおよびExcelファイルを選択してください。`
|
||||||
|
})
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function onUploadFinish(){
|
function uploadFinished(){
|
||||||
$q.notify({
|
$q.notify({
|
||||||
message:"ファイルアップロードしました!",
|
type: 'info',
|
||||||
caption:"通知",
|
caption:"通知",
|
||||||
type:"positive"
|
message: 'ファイルの読込が完了しました。'
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
title: string;
|
title: string;
|
||||||
uploadUrl:string;
|
uploadUrl:string;
|
||||||
}
|
}
|
||||||
const props = withDefaults(defineProps<Props>(), {
|
const props = withDefaults(defineProps<Props>(), {
|
||||||
title:"設計書から導入する(csv or excel)",
|
title:"設計書から導入する(csv or excel)",
|
||||||
uploadUrl:process.env.KAB_BACKEND_URL
|
uploadUrl:process.env.KAB_BACKEND_URL
|
||||||
});
|
});
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
<style lang="scss">
|
<style lang="scss">
|
||||||
|
|
||||||
|
|||||||
1174
frontend/yarn.lock
1174
frontend/yarn.lock
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user