Python3 + Flask3 + SQLite3 Webアプリ開発メモ

## srappli-flask Webアプリ

　SRアプリという名のWebアプリを`Python3 + Flask3 + SQLite3` で開発しています。これはその個人的な開発メモです。SRが何の略なのかは諸事情で明記できません（汗;）。

　これからしばらくの間ちょくちょく更新していくと思いますので、よろしくお願いします。

### フォルダパス構成
<img width="450" alt="スクリーンショット 2019-06-10 23.33.58.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/124810/57c3a4a9-28db-7857-645a-13a0c5048d91.png">

### srappli-flask/instanceフォルダ

SQLiteデータベースのインスタンスを格納するフォルダです。


```python:create_installdb.py
import sqlite3
DROP_INSTALLS = "DROP TABLE IF EXISTS installs"
CREATE_INSTALLS = '''
 CREATE TABLE installs
 (
 id INTEGER PRIMARY KEY AUTOINCREMENT,
 applidate DATE,
 applicantsid TEXT,
 applicantsdiv TEXT,
 applicantsname TEXT,
        ledgerno TEXT,
        hopedate DATE,
        enddate DATE,
        stragebin TEXT
    )
'''

conn = sqlite3.connect('installdb.sqlite3')
cur = conn.cursor()
cur.execute(DROP_INSTALLS)
cur.execute(CREATE_INSTALLS)
conn.commit()
conn.close
```

```python:insert_installdb.py
#coding=utf-8
import sqlite3

INSERT_INSTALL = '''
    INSERT INTO installs (
            applidate,
            applicantsid,
            applicantsdiv,
            applicantsname,
            ledgerno,
            hopedate,
            enddate,
            stragebin
        )
        VALUES (
            date('2020-06-01'),
            'Z1234567',
            'ホゲホゲ開発部',
            '青木 孝',
            '678934',
            date('2020-07-01'),
            date('2020-09-30'),
            '1-2-3'
        )
'''
SELECT_INSTALL = "SELECT * FROM installs"

conn = sqlite3.connect('installdb.sqlite3')

cur = conn.cursor()
cur.execute(INSERT_INSTALL)
conn.commit()

cur.execute(SELECT_INSTALL)
result = cur.fetchall()
print(result)
conn.close()
```
```python:insert_stragebintable.py
#coding=utf-8
import sqlite3

SELECT_INSTALL = "SELECT * FROM stragebins"

conn = sqlite3.connect('installdb.sqlite3')

cur = conn.cursor()

for i in range(1,5):
    for j in range(1,3):
        for k in range(1,5):
            insertbin = '''
                INSERT INTO stragebins
                (cabinetno,binno,seqno)
                VALUES (%d,%d,%d)
            ''' %(i,j,k)
            cur.execute(insertbin)

conn.commit()

cur.execute(SELECT_INSTALL)
result = cur.fetchall()
print(result)
conn.close()
```

## srappli-flask/webフォルダ

### srappli-flask/web/employees.py

```python:employees.py
from flask import(
    Blueprint, render_template,
    request, redirect, url_for
)
from web.installdb import get_db
from web.files import save_csv, read_employees_csv
​
bp = Blueprint('employees', __name__)
​
@bp.route('/employees', methods = ['GET'])
def all():
    installdb = get_db()
    SELECT_EMPLOYEES = '''
        SELECT 
            employees.id, 
            employees.name, 
            employees.afficode, 
            departments.abbreviation
        FROM employees JOIN departments
            ON employees.afficode = departments.id
    '''
    alldata = installdb.execute(SELECT_EMPLOYEES).fetchall()
    return render_template('employees/all.html', employees = alldata)
​
@bp.route('/employees/upload', methods = ['GET', 'POST'])
def upload():
    if request.method == 'POST':
        if 'file' in request.files:
            file = request.files['file']
            save_csv(file)
            datadict = read_employees_csv(file.filename)
            installdb = get_db()
            installdb.execute('DELETE FROM employees')
            for data in datadict:
                installdb.execute(
                    "INSERT INTO employees (id, name, afficode) VALUES (?, ?, ?)",
                    ( data['id'], data['name'], data['afficode'] )
                )
            installdb.commit()
        return redirect(url_for('employees.all'))
​
    return render_template('employees/upload.html')

```

### srappli-flask/web/files.py

```python:files.py
from flask import current_app
import os
import csv
​
def save_img(file):
    file.save(os.path.join(current_app.config['UPLOAD_FOLDER'],'img',file.filename))
​
def save_csv(file):
    file.save(os.path.join(current_app.config['UPLOAD_FOLDER'],'csv',file.filename))
​
def read_departments_csv(filename):
    datalist=[]
    with open(os.path.join(current_app.config['UPLOAD_FOLDER'], 'csv',
        filename),encoding="utf-8") as datafile:
        datareader=csv.reader(datafile)
        for row in datareader:
                datadict={}
                datadict['id']=row[0]
                datadict['abbreviation']=row[1]
                datalist.append(datadict)
​
        return datalist
​
def read_employees_csv(filename):
    datalist=[]
    with open(os.path.join(current_app.config['UPLOAD_FOLDER'], 'csv',
        filename),encoding="utf-8") as datafile:
        datareader=csv.reader(datafile)
        for row in datareader:
            datadict={}
            datadict['name']=row[0]
            datadict['id']=row[1]
            datadict['afficode']=row[2]
            datalist.append(datadict)
        return datalist
​
def write_file(filename, str):
    with open(os.path.join(current_app.config['UPLOAD_FOLDER'], 'csv',
        filename), 'w') as datafile:
        datafile.write(str)
```

### srappli-flask/web/installdb.py

```python:installdb.py
import sqlite3
from flask import current_app, g
​
def get_db():
    if 'installdb' not in g:
        g.installdb = sqlite3.connect(
            current_app.config['INSTALLDB'],
            detect_types = sqlite3.PARSE_DECLTYPES
        )
        g.installdb.row_factory = sqlite3.Row
    return g.installdb
​
def close_db(e = None):
    installdb = g.pop('installdb', None)
    if installdb is not None:
        installdb.close()
​
def init_app(app):
    app.teardown_appcontext(close_db)
```


### srappli/web/installs.py

```python:installs.py
import sys
from tkinter import messagebox
from flask import(
    Blueprint, render_template,request, redirect, url_for
)
from web.installdb import get_db
from web.files import save_img, write_file
from web.utility import ValideteUtil #, EmailUtil
​
​
bp = Blueprint('installs', __name__)
​
@bp.route('/', methods = ['GET'])
def index():
    return render_template('index.html')
​
@bp.route('/installs', methods = ['GET'])
def all():
    installdb = get_db()
    alldata = installdb.execute('SELECT * FROM installs').fetchall()
    return render_template('installs/all.html', installs = alldata)
​
@bp.route('/installs/new', methods = ['GET', 'POST'])
def new():
    installdb = get_db()
    stragebins = installdb.execute('SELECT * FROM stragebins').fetchall()
    departments = installdb.execute('SELECT * FROM departments').fetchall()
    if request.method == 'POST':
        if ValideteUtil.isDecimal(request.form['applicantsid']) == False:
            applicantsid_message = '※社員ID：全て数値で入力してください',
            return render_template('installs/new.html',
                stragebins = stragebins, departments = departments,
                applicantsid_message = applicantsid_message
            )
        if ValideteUtil.isDecimal(request.form['ledgerno']) == False:
            ledgerno_message = '※台帳No.：全て数値で入力してください'
            return render_template('installs/new.html',
                stragebins = stragebins, departments = departments,
                ledgerno_message = ledgerno_message
            )
        install_data = (
            request.form['applidate'],
            request.form['applicantsid'],
            request.form['applicantsdiv'],
            request.form['applicantsname'],
            request.form['ledgerno'],
            request.form['hopedate'],
            request.form['enddate'],
            request.form['stragebin']
        )
        installdb.execute(
            "INSERT INTO installs (applidate, applicantsid, applicantsdiv, applicantsname, ledgerno, hopedate, enddate, stragebin) VALUES (?, ?, ?, ?, ?, ?, ?, ?)",
            install_data
        )
        installdb.commit()
        #EmailUtil.sendEmail()
        return redirect(url_for('installs.all'))
​
    return render_template(
        'installs/new.html', 
        stragebins = stragebins, departments = departments
    )
​
@bp.route('/installs/show/<install_id>', methods = ['GET', 'POST'])
def show(install_id):
    if request.method == 'GET':
        installdb = get_db()
        install = installdb.execute('SELECT * FROM installs WHERE id = ?', install_id).fetchone()
        print(install)
        return render_template('installs/show.html', install = install)
​
@bp.route('/installs/edit/<install_id>', methods = ['GET', 'POST'])
def edit(install_id):
    installdb = get_db()
    if request.method == 'POST':
        install_data = (
            request.form['applidate'],
            request.form['applicantsid'],
            request.form['applicantsdiv'],
            request.form['applicantsname'],
            request.form['ledgerno'],
            request.form['hopedate'],
            request.form['enddate'],
            request.form['stragebin'],
            install_id
        )
        installdb.execute(
            "UPDATE installs SET applidate = ?, applicantsid = ?, applicantsdiv = ?, applicantsname = ?, ledgerno = ?, hopedate = ?, enddate = ?, stragebin = ? where id = ?",
            install_data
        )
        installdb.commit()
        return redirect(url_for('installs.all'))
​
    install = installdb.execute(
        "SELECT * FROM installs where id = ?", (install_id,)
    ).fetchone()
    stragebins = installdb.execute('SELECT * FROM stragebins').fetchall()
    departments = installdb.execute('SELECT * FROM departments').fetchall()
    return render_template(
        'installs/edit.html',
        install = install, stragebins = stragebins, departments = departments
    )
​
@bp.route('/installs/delete/<install_id>', methods = ['GET'])
def delete(install_id):
    installdb = get_db()
    installdb.execute(
        "DELETE from installs where id = ?", (install_id,)
    )
    installdb.commit()
    return redirect(url_for('installs.all'))
​
@bp.route('/installs/upload/<install_id>', methods = [ 'GET', 'POST' ])
def upload(install_id):
    db = get_db()
    if request.method == 'POST':
        if 'file' in request.files:
            file = request.files['file']
            save_img(file)
            db.execute(
                "UPDATE installs SET stragebin = ? WHERE id = ?",
                (file.filename, install_id)
            )
            db.commit()
​
        return redirect(url_for('installs.show', install_id = install_id))
​
    install = db.execute('SELECT * FROM installs WHERE id = ?', install_id).fetchone()
    return render_template('installs/upload.html', install = install)                                                                                           
@bp.route('/installs/write', methods = [ 'GET' ])
def write():
    csv_str = ""
    db = get_db()
    alldata = db.execute('SELECT * FROM installs').fetchall()
    for data in alldata:
        csv_str += ",".join( [ data['ledgerdno'], data['applicantsname'], data['hopedate'] ] )
        csv_str += "\n"
    write_file("installs.csv", csv_str)
    return render_template('installs/write.html', str = csv_str)
```

### srappli/web/stragebins.py

```python:stragebins.py
import sys
from tkinter import messagebox
from flask import(
    Blueprint, render_template,request, redirect, url_for
)
from web.installdb import get_db
from web.files import save_img, write_file
from web.utility import ValideteUtil #, EmailUtil
​
​
bp = Blueprint('installs', __name__)
​
@bp.route('/', methods = ['GET'])
def index():
    return render_template('index.html')
​
@bp.route('/installs', methods = ['GET'])
def all():
    installdb = get_db()
    alldata = installdb.execute('SELECT * FROM installs').fetchall()
    return render_template('installs/all.html', installs = alldata)
​
@bp.route('/installs/new', methods = ['GET', 'POST'])
def new():
    installdb = get_db()
    stragebins = installdb.execute('SELECT * FROM stragebins').fetchall()
    departments = installdb.execute('SELECT * FROM departments').fetchall()
    if request.method == 'POST':
        if ValideteUtil.isDecimal(request.form['applicantsid']) == False:
            applicantsid_message = '※社員ID：全て数値で入力してください',
            return render_template('installs/new.html',
                stragebins = stragebins, departments = departments,
                applicantsid_message = applicantsid_message
            )
        if ValideteUtil.isDecimal(request.form['ledgerno']) == False:
            ledgerno_message = '※台帳No.：全て数値で入力してください'
            return render_template('installs/new.html',
                stragebins = stragebins, departments = departments,
                ledgerno_message = ledgerno_message
            )
        install_data = (
            request.form['applidate'],
            request.form['applicantsid'],
            request.form['applicantsdiv'],
            request.form['applicantsname'],
            request.form['ledgerno'],
            request.form['hopedate'],
            request.form['enddate'],
            request.form['stragebin']
        )
        installdb.execute(
            "INSERT INTO installs (applidate, applicantsid, applicantsdiv, applicantsname, ledgerno, hopedate, enddate, stragebin) VALUES (?, ?, ?, ?, ?, ?, ?, ?)",
            install_data
        )
        installdb.commit()
        #EmailUtil.sendEmail()
        return redirect(url_for('installs.all'))
​
    return render_template(
        'installs/new.html', 
        stragebins = stragebins, departments = departments
    )
​
@bp.route('/installs/show/<install_id>', methods = ['GET', 'POST'])
def show(install_id):
    if request.method == 'GET':
        installdb = get_db()
        install = installdb.execute('SELECT * FROM installs WHERE id = ?', install_id).fetchone()
        print(install)
        return render_template('installs/show.html', install = install)
​
@bp.route('/installs/edit/<install_id>', methods = ['GET', 'POST'])
def edit(install_id):
    installdb = get_db()
    if request.method == 'POST':
        install_data = (
            request.form['applidate'],
            request.form['applicantsid'],
            request.form['applicantsdiv'],
            request.form['applicantsname'],
            request.form['ledgerno'],
            request.form['hopedate'],
            request.form['enddate'],
            request.form['stragebin'],
            install_id
        )
        installdb.execute(
            "UPDATE installs SET applidate = ?, applicantsid = ?, applicantsdiv = ?, applicantsname = ?, ledgerno = ?, hopedate = ?, enddate = ?, stragebin = ? where id = ?",
            install_data
        )
        installdb.commit()
        return redirect(url_for('installs.all'))
​
    install = installdb.execute(
        "SELECT * FROM installs where id = ?", (install_id,)
    ).fetchone()
    stragebins = installdb.execute('SELECT * FROM stragebins').fetchall()
    departments = installdb.execute('SELECT * FROM departments').fetchall()
    return render_template(
        'installs/edit.html',
        install = install, stragebins = stragebins, departments = departments
    )
​
@bp.route('/installs/delete/<install_id>', methods = ['GET'])
def delete(install_id):
    installdb = get_db()
    installdb.execute(
        "DELETE from installs where id = ?", (install_id,)
    )
    installdb.commit()
    return redirect(url_for('installs.all'))
​
@bp.route('/installs/upload/<install_id>', methods = [ 'GET', 'POST' ])
def upload(install_id):
    db = get_db()
    if request.method == 'POST':
        if 'file' in request.files:
            file = request.files['file']
            save_img(file)
            db.execute(
                "UPDATE installs SET stragebin = ? WHERE id = ?",
                (file.filename, install_id)
            )
            db.commit()
​
        return redirect(url_for('installs.show', install_id = install_id))
​
    install = db.execute('SELECT * FROM installs WHERE id = ?', install_id).fetchone()
    return render_template('installs/upload.html', install = install)                                                                                           
@bp.route('/installs/write', methods = [ 'GET' ])
def write():
    csv_str = ""
    db = get_db()
    alldata = db.execute('SELECT * FROM installs').fetchall()
    for data in alldata:
        csv_str += ",".join( [ data['ledgerdno'], data['applicantsname'], data['hopedate'] ] )
        csv_str += "\n"
    write_file("installs.csv", csv_str)
    return render_template('installs/write.html', str = csv_str)
```

### srappli/web/utility.py
```python:utility.py
import re
import smtplib
#from flask_mail import Mail, Message
​
'''
class EmailUtil:
​
    @staticmethod
    def sendEmail():
        app.config.update(dict(
            MAIL_SERVER = 'smtp.ogis-ri.co.jp',
            MAIL_PORT = 465,
            MAIL_USE_TLS = False,
            MAIL_USE_SSL = True,
            MAIL_USERNAME = 'UserName',
            MAIL_PASSWORD = 'password'
        ))
​
        mail = Mail(app)
        msg = Message('Test', sender='Mail-Addrss@hogehoge.co.jp', recipients=['foo_bakako@hogehoge.co.jp'])
        msg.body = 'This is a test email'
        mail.send(msg)
​
        return 'done'
'''
class ValideteUtil: 
​
    @staticmethod
    def isInteger(value):
        """
        整数チェック
        :param value: チェック対象の文字列
        :rtype: チェック対象文字列が、全て数値の場合 True
        """
        return re.match(r"^\d+$", value) is not None
​
    @staticmethod
    def isDecimal(value):
        '''
        小数チェック
        :param value: チェック対象の文字列
        :rtype: チェック対象文字列が、整数または小数の場合 True True
        '''
        return re.match(r"^[+-]?[0-9]*[.]?[0-9]+$", value) is not None
        
    @staticmethod
    def isAlpha(value):
        """
        半角英字チェック
        :param value: チェック対象の文字列
        :rtype: チェック対象文字列が、全て半角英字の場合 True
        """
        return re.match(r"^[a-z]+$", value) is not None
​
    @staticmethod
    def isAlphaNumeric(value):
        """
        半角英数字チェック
        :param value: チェック対象の文字列
        :rtype: チェック対象文字列が、全て半角英数字の場合 True
        """
        return re.match(r"^\w+$", value) is not None
​
    @staticmethod
    def isHarf(value):
        """
        半角文字チェック
        :param value: チェック対象の文字列
        :rtype: チェック対象文字列が、全て半角文字の場合 True (半角カナは含まない)
        """
        return re.match(r"^[\x20-\x7E]+$", value) is not None
​
    @staticmethod
    def isHarfKana(value):
        """
        半角カナチェック
        :param value: チェック対象の文字列
        :rtype: チェック対象文字列が、全て半角カナの場合 True
        """
        return re.match(r"^[ｦ-ﾟ]+$", value) is not None
​
    @staticmethod
    def isFull(value):
        """
        全角文字チェック
        :param value: チェック対象の文字列
        :rtype: チェック対象文字列が、全て全角文字の場合 True 
        """
        return re.match(r"^[^\x01-\x7E]+$", value) is not None
```
### srappli/web/departments.py

```python:departments.py
from flask import(
    Blueprint, render_template,
    request, redirect, url_for
)
from web.installdb import get_db
from web.files import save_csv, read_departments_csv
​
bp = Blueprint('departments', __name__)
​
@bp.route('/departments', methods = ['GET'])
def all():
    installdb = get_db()
    alldata = installdb.execute('SELECT * FROM departments').fetchall()
    return render_template('departments/all.html', departments = alldata)
​
@bp.route('/departments/upload', methods = ['GET', 'POST'])
def upload():
    if request.method == 'POST':
        if 'file' in request.files:
            file = request.files['file']
            save_csv(file)
            datadict = read_departments_csv(file.filename)
            installdb = get_db()
            installdb.execute('DELETE FROM departments')
            for data in datadict:
                installdb.execute(
                    "INSERT INTO departments (id, abbreviation) VALUES (?, ?)",
                    (data['id'], data['abbreviation'])
                )
            installdb.commit()
        return redirect(url_for('departments.all'))
​
    return render_template('departments/upload.html')
```

### srappli/web/__init__.py

```python:__init__.py
from flask import Flask
import os
​
def create_app():
    app = Flask(__name__)
​
    from . import installs
    app.register_blueprint(installs.bp)
​
    from . import stragebins
    app.register_blueprint(stragebins.bp)
​
    from . import departments
    app.register_blueprint(departments.bp)
​
    from . import employees
    app.register_blueprint(employees.bp)
​
    app.config.from_mapping(
        SELECT_KEY = 'temp',
        INSTALLDB = os.path.join(app.instance_path, 'installdb.sqlite3'),
    )
​
    from . import installdb
    installdb.init_app(app)
​
    UPLOAD_FOLDER = 'C:/Dev/flask/srappli-flask/web/static'
    app.config['UPLOAD_FOLDER'] = UPLOAD_FOLDER
​
    return app
```

## srappli-flask/web/staticフォルダ

[calendar.js を利用させていただいたサイトさまはこちら](https://web-designer.cman.jp/javascript_ref/keybord/calendar/)

```javascript:calendar.js
// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
//  【 カレンダー選択入力 】  http://www.cman.jp/
//   商用,改変,再配布はすべて自由ですですが、動作保証はありません
// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
//    maintenance history
//    Ver   Date        contents
//    0.9   2016/6/20   New
//    0.91  2016/6/21   カレンダ表示位置修理
//    0.92  2017/4/28   ユーザ様ご指摘による不具合修正
//    0.93  2018/9/28   ユーザ様ご指摘による不具合修正                   
// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
//使用方法
// https://web-designer.cman.jp/javascript_ref/keybord/calendar/
//【注意】
//引数やユーザ設定内容についてはノーチェックです
//解析しやすいようにコメントを多く入れています。
//JavaScriptのファイルサイズを削減する場合は、コメントやスペースを消してください。
//再配布する場合は、当サイトのJavaScriptが元であることを記載ください。
// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━


var cmanCLD_VAR = {};

// ----- 初期イベントの登録 ------------------------------------------------
if ( window.addEventListener ){window.addEventListener("load", cmanCLD_JS_init, false);}
else if( window.attachEvent )     {window.attachEvent( 'onload', cmanCLD_JS_init );}


//======================================================================
//	初期処理（オンロード時）
//======================================================================
function cmanCLD_JS_init(){
	var wID		= '';
	var wObjAt;
	// ----- 対象タグの一覧を配列に格納 ----------------------------------
	var wTagList = document.getElementsByTagName('input');
	// ----- input type="date","text" を対象にイベント登録する -----------
	for(var i = 0; i < wTagList.length; i++){
		// ----- "date"と"text"だけを対象とする ---------------------
		if((wTagList[i].type.toLowerCase() != "date")&&(wTagList[i].type.toLowerCase() != "text")){
			continue;	// 次の要素へ
		}
		// ----- 属性"cmanCLDat"を取得 ---------------------------
		wObjAt = wTagList[i].getAttribute("cmanCLDat");
		if(wObjAt === null){
			wObjAt = '';
		}
		// ----- "text"の場合は属性"cmanCLDat"が実在しない場合は対象外
     if(wObjAt ==''){
			continue;	// 次の要素へ
		}
		// ----- 属性で「OFF」（未使用）が定義されている場合は対象外 --------
		wObjAt = wObjAt.replace(/\s+/g, "");
		if(wObjAt.match(/USE:OFF/i)){
			continue;	// 次の要素へ
		}
		// ----- "date"でブラウザが"date"に対応している場合は動作させない -
		//      （二重にパレットが出る）
		if(wTagList[i].type.toLowerCase() == "date"){

			// ブラウザがdateに対応しているかチェック
			var wObjTest = document.createElement("input");
			wObjTest.setAttribute("type", "date");

			if(wObjTest.type.toLowerCase() == "date"){
				continue;	// 次の要素へ
			}
		}
		// ----- 対象の要素にカラーパレットを開くイベント（KeyDown時）を登録 --
		wTagList[i].onkeydown	= cmanCLD_JS_open;
		wTagList[i].onclick	= cmanCLD_JS_open;
	}
	// ----- カレンダーを閉じるためのイベント登録 ----------------------------
  document.body.onclick	= cmanCLD_JS_bodyClick;
	window.onscroll		= cmanCLD_JS_cl;
}
//======================================================================
//	カレンダー以外がクリックされた場合は、カレンダを閉じる
//======================================================================
function cmanCLD_JS_bodyClick(e){

  var wObjClick = e.target;
 // ----- カレンダーが開いていない場合は対象外 --------------------------	 
 if(document.getElementById(cmanCLD_VAR["popId"])){
	}else{
		return;
	}
	// ----- クリックされた要素の親要素に「cmanCLD」が実在する場合は対象外 ------
	var wObjAt = wObjClick.getAttribute("cmanCLDat");
	if((wObjAt === null)||(wObjAt == '')){
	}else{
		return;
	}
	// ----- クリックされた要素の親要素に「cmanCLD」が実在する場合は対象外 -------
	if(wObjClick.id.match(/^cmanCLD/)){
		return;
	} 
	// ----- クリックされた要素の親要素に「cmanCLD」が実在する場合は対象外 -------
	var wOyaObj = wObjClick;
	for(var j = 0; j < 10; j++){
	  wOyaObj = wOyaObj.parentNode;
	  if((typeof wOyaObj === 'object')&&(wOyaObj.tagName.toLowerCase() != 'html')){
	    if(wOyaObj.id.match(/^cmanCLD/)){
	      return;
	    } 
	   }else{
	     break;
	   }
	}
	// ----- カレンダーが開いている場合は閉じる --------------------------
  cmanCLD_JS_cl();
}
//======================================================================
//	カレンダーを開く	
//======================================================================
function cmanCLD_JS_open(e){
	// ----- カレンダーが開いている場合は閉じる -----------------------------
  cmanCLD_JS_cl();
	// ----- 対象外キーは処理を抜ける -----------------------------------
  switch (e.keyCode){
	  case 9	:		// tab
	  case 16	:		// shift
		  return;
		  break;
	}
	// ----- 日付入力エリア --------------------------------------------
  	cmanCLD_VAR["objValue"] = e.target;
	// ----- 選択済み日付をハッシュ変数に保存 -----------------------------
  	cmanCLD_VAR["selectedDate"] = '';
	if(cmanCLD_JS_DateChk(cmanCLD_VAR["objValue"].value)){
		var wSplit = cmanCLD_VAR["objValue"].value.split("-");

		if(wSplit.length == 3){
			cmanCLD_VAR["selectedDate"] = cmanCLD_JS_dateEdit(wSplit[0], wSplit[1], wSplit[2]);
		}
	}
	// ----- カレンダ編集＆表示 -----------------------------------------
  	if(cmanCLD_VAR["selectedDate"] == ''){
		cmanCLD_JS_create('','');
	}
	else{
		cmanCLD_JS_create( new Date(cmanCLD_VAR["selectedDate"]).getFullYear(),  new Date(cmanCLD_VAR["selectedDate"]).getMonth() + 1);
	}
	// ----- 押されたキーはクリアする -------------------------------------
  	e.keyCode = 0;
	return false;

}
//======================================================================
//	表示年月変更
//======================================================================
function cmanCLD_JS_res(argYM, argUD){
	var wNextOutYMD;
	wNextOutYMD = new Date( cmanCLD_VAR["outYYYY"], parseInt(cmanCLD_VAR["outMM"]) - 1, 1);
	// ----- 次に表示する年月を求める ------------------------------------
  	if(('outYYYY' in cmanCLD_VAR)&&('outMM' in cmanCLD_VAR)){
		if(argYM == 'y'){
			if(argUD == 'u'){				wNextOutYMD.setYear(wNextOutYMD.getFullYear() + 1);
			}else{				wNextOutYMD.setYear(wNextOutYMD.getFullYear() - 1);
			}
		}else{
			if(argUD == 'u'){				wNextOutYMD.setMonth(wNextOutYMD.getMonth() + 1);
			}else{
				wNextOutYMD.setMonth(wNextOutYMD.getMonth() - 1);
			}
		}
	}else{
		wNextOutYMD = new Date();
	}
	// ----- カレンダ編集＆表示 -----------------------------------------
  	cmanCLD_JS_edit( wNextOutYMD.getFullYear(),  wNextOutYMD.getMonth() + 1);
}
//======================================================================
//	カレンダーの編集
//======================================================================
function cmanCLD_JS_edit(argYYYY, argMM){
	var wObjDate_FirstDay;         // 月初
	var wObjDate_LastDay;          // 月末
	var wStr_FirstDay_Week  = 0;   // 月初の曜日
	var wStr_LastDay_Week   = 0;   // 月末の曜日
	var wObjDate_LastMonth;        // 前月
	var wObjDate_NextMonth;        // 翌月
	var wObjDate_JpFirstDay;       // 元号判定用の元号別月初
	var wOutY_JpName        = '';  // 元号
	var wOutY_JpYY          = '';  // 和暦年
	var wDayList            = [];  // カレンダーに表示する日付
	var wDayListIdx         = 0;
	var wDayListTargetIdxF  = 0;
	var wDayListTargetIdxT  = 0;
	var wStrNowDate         = 0;   // 現在日付（表示のカレンダの月と違う場合は0）
	var wLang               = "";
	// ----- 曜日表示テーブル -----------------------------------------
  var wWeekJA	= [ '日', '月', '火', '水', '木', '金', '土' ];
	var wWeekEN	= [ 'Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat' ];

	// ----- 和暦の表示テーブル（元号変更時は追加が必要） --------------------
  var wG_YMS	= [ '1868-01-25', '1912-07-30', '1926-12-25', '1989-01-08' , '2019-05-01' ];
	var wG_STR	= [ '明治', '大正', '昭和', '平成', '令和' ];

	// ----- カレンダー枠のID設定 --------------------------------------
  cmanCLD_VAR["popId"]	= 'cmanCLD_POP'; // POP枠のID
	// ----- 属性"cmanCLDat"より言語を取得 -----------------------------
  var wObjAt = cmanCLD_VAR["objValue"].getAttribute("cmanCLDat").replace(/\s+/g, "");
	if(wObjAt.match(/LANG:EN/i))	{wLang = 'EN';}
	else							{wLang = 'JA';}
	// ----- 表示する日付を設定 ----------------------------------------
  if((argYYYY == '')||(argMM=='')){
		wObjDate_FirstDay = new Date(new Date().getFullYear(), new Date().getMonth() , 1);	// 当日の月初
	}else{
		wObjDate_FirstDay = new Date(argYYYY, argMM - 1, 1);
	}

	// 明治以前は表示しない
	if(wObjDate_FirstDay.getTime() < new Date(wG_YMS[0]).getTime()){
		wObjDate_FirstDay = new Date(wG_YMS[0]);
	}
	// ----- 月末を調べる ---------------------------------------------
  wObjDate_LastDay	= new Date(wObjDate_FirstDay.getFullYear(), wObjDate_FirstDay.getMonth() + 1, 0);
	// ----- 表示する和暦年・元号を設定 ----------------------------------
  for (var i = wG_YMS.length - 1; i >=0; i--){
		var wSplit = wG_YMS[i].split("-");
		wObjDate_JpFirstDay =  new Date(wSplit[0], wSplit[1] - 1, 1);			// Ver0.92 Insert
		if(wObjDate_FirstDay.getTime() >= wObjDate_JpFirstDay.getTime()){
			wOutY_JpName = wG_STR[i];
			wOutY_JpYY   = wObjDate_FirstDay.getFullYear() - wObjDate_JpFirstDay.getFullYear() + 1;
			if(wOutY_JpYY == 1){wOutY_JpYY = '元';}
			break;
		}
	}
	// ----- 当日がカレンダに実在するか確認する ----------------------------
  wStrNowDate = cmanCLD_JS_dateEdit( new Date().getFullYear(), new Date().getMonth() + 1, new Date().getDate());
	// ----- 表示カレンダー設定（上部の年月） ------------------------------
  document.getElementById('cmanCLD_ID_outy').innerHTML	= wObjDate_FirstDay.getFullYear() + '年';
	if(wLang == 'JA'){
		document.getElementById('cmanCLD_ID_outy').innerHTML	+= '<div style="font-size:80%;font-weight: normal;padding-top:1px;text-align: center;">' + wOutY_JpName + wOutY_JpYY + '年</div>';
	}
	document.getElementById('cmanCLD_ID_outm').innerText	= (wObjDate_FirstDay.getMonth() + 1) + '月';
	// ----- 月初・月末の曜日を調べる ------------------------------------
  wStr_FirstDay_Week	= wObjDate_FirstDay.getDay();		// 0:日曜
	wStr_LastDay_Week	= wObjDate_LastDay.getDay();		// 0:日曜
	// ----- 前月末日を調べる ------------------------------------------
  wObjDate_LastMonth = new Date(wObjDate_FirstDay.getFullYear(), wObjDate_FirstDay.getMonth(), 0);
	wObjDate_NextMonth = new Date(wObjDate_FirstDay.getFullYear(), wObjDate_FirstDay.getMonth() + 1, 1);		// Ver0.93 Update
	// ----- 1行目の前月最終分を配列に格納 -------------------------------
  var wLastMonthDay = wObjDate_LastMonth.getDate() - wStr_FirstDay_Week + 1;
	if(wStr_FirstDay_Week != 0){
		for ( var j = 0; j < wStr_FirstDay_Week; j++){
			wDayList[wDayListIdx++] = cmanCLD_JS_dateEdit(wObjDate_LastMonth.getFullYear(), wObjDate_LastMonth.getMonth() + 1, wLastMonthDay++);
		}
	}
	// ----- 当月分を配列に格納 ----------------------------------------
  wDayListTargetIdxF = wDayListIdx;
	for ( var j = 1; j <= wObjDate_LastDay.getDate(); j++){
		wDayList[wDayListIdx++] = cmanCLD_JS_dateEdit(wObjDate_FirstDay.getFullYear(), wObjDate_FirstDay.getMonth() + 1, j);
	}
	wDayListTargetIdxT = wDayListIdx - 1;
	// ----- 最終行目の翌月最終分を配列に格納 ----------------------------
  var wNextMonthDay = 1;
	if(wStr_LastDay_Week != 6){
		for ( var j = wStr_LastDay_Week; j < 6; j++){
			wDayList[wDayListIdx++] = cmanCLD_JS_dateEdit(wObjDate_NextMonth.getFullYear(), wObjDate_NextMonth.getMonth() + 1, wNextMonthDay++);		// Ver0.93 Update
		}
	}
	// ----- カレンダー部分の編集 ---------------------------------------
  var wCldTbl  = '';
	wCldTbl		+=	'<table id="cmanCLD_ID_tbl1">';

	// ----- カレンダー部分（曜日）の編集 ----------------------------------
  var wWeekTbl;
	if(wLang == 'JA'){wWeekTbl = wWeekJA.concat();}
	else             {wWeekTbl = wWeekEN.concat();}
	wCldTbl		+=	'<tr><th style="color: #ff3333;">'+wWeekTbl[0]+'<  h><th>'+wWeekTbl[1]+'<  h><th>'+wWeekTbl[2]+'<  h><th>'+wWeekTbl[3]+'<  h><th>'+wWeekTbl[4]+'<  h><th>'+wWeekTbl[5]+'<  h><th style="color: #0033ff;">'+wWeekTbl[6]+'<  h><  r>';
	// ----- カレンダー部分（日付）の編集 ----------------------------------
  for (var i = 0; i < wDayList.length; i++){
		if((i % 7) == 0){
			wCldTbl		+=	'<tr>';
		}
		if	(i < wDayListTargetIdxF){
			wCldTbl		+=	'<td class="cmanCLD_CSS_StrOff" id="cmanCLD_ID_col' + i + '" onclick="cmanCLD_JS_sel(\'' + wDayList[i] + '\')">' + new Date(wDayList[i]).getDate() + '<  d>';
		}
		else if	(i > wDayListTargetIdxT){
			wCldTbl		+=	'<td class="cmanCLD_CSS_StrOff" id="cmanCLD_ID_col' + i + '" onclick="cmanCLD_JS_sel(\'' + wDayList[i] + '\')">' + new Date(wDayList[i]).getDate() + '<  d>';
		}
		else{
			wCldTbl		+=	'<td class="cmanCLD_CSS_StrOn" id="cmanCLD_ID_col' + i + '" onclick="cmanCLD_JS_sel(\'' + wDayList[i] + '\')"';
			var wStyle	= '';
			if(cmanCLD_VAR["selectedDate"] == wDayList[i]){
				wStyle	+=	'background-color:#ffcccc;';
			}
			if(wStrNowDate == wDayList[i]){
				wStyle	+=	'border:1px solid #0099ff;';
			}
			if(wStyle !=''){
				wCldTbl	+=	' style="'+wStyle+'"';
			}
			wCldTbl		+=	'>' + new Date(wDayList[i]).getDate() + '<  d>';
		}
		if((i % 7) == 6){
			wCldTbl		+=	'<  r>';
		}
	}
	wCldTbl		+=	'<  able>';
	document.getElementById('cmanCLD_ID_dateList').innerHTML = wCldTbl;
	// ----- カレンダの表示 --------------------------------------------
  cmanCLD_VAR["objPop"].style.display	= '';
	cmanCLD_VAR["outYYYY"]	= wObjDate_FirstDay.getFullYear();
	cmanCLD_VAR["outMM"]	= wObjDate_FirstDay.getMonth() + 1;
}
//======================================================================
//	カレンダーの雛形枠作成
//======================================================================
function cmanCLD_JS_create(argYYYY, argMM){
	cmanCLD_VAR["popId"]	= 'cmanCLD_POP';		// POP枠のID
	if(document.getElementById(cmanCLD_VAR["popId"])){return;}
	// ----- CSS定義 ------------------------------------------------
  var wCss =	'<style type="text/css">';
	wCss	+=	'#cmanCLD_ID_area {' +
				'width: 100%;' + 
				'max-width:260px;' + 
				'border: 1px solid #000;' + 
				'font-size: 9pt;' + 
				'background-color: #fff;' +
				'line-height: 1.1em;' +
				'letter-spacing: 1px;' +
			'}';
	wCss	+=	'#cmanCLD_ID_tbl1 {' + 
				'width: 100%;' + 
				'text-align: center;' + 
				'border-collapse:collapse;' + 
				'border: 1px solid #fff;' + 
				'font-size: 10pt;' + 
				'color: #333;' + 
			'}';
	wCss	+=	'#cmanCLD_ID_tbl1 th {' + 
				'background-color: #eee;' + 
				'padding: 3px;' + 
				'border-top: 1px solid #666;' + 
				'border-bottom: 1px solid #ccc;' + 
				'font-weight: normal;' + 
			'}';
	wCss	+=	'#cmanCLD_ID_tbl1 td {' + 
				'padding: 3px;' + 
				'cursor: pointer;' + 
				'font-weight: normal;' + 
			'}';
	wCss	+=	'#cmanCLD_ID_tbl1 td:hover {' + 
				'background-color: #ddeeff;' + 
			'}';
	wCss	+=	'#cmanCLD_ID_ym {' + 
				'width: 100%;' + 
				'text-align: center;' + 
				'border-collapse:collapse;' + 
				'border: 1px solid #fff;' + 
				'font-size: 10pt;' + 
				'color: #333;' + 
			'}';
	wCss	+=	'.cmanCLD_CSS_btm {' + 
				'margin: 5px;' + 
				'width: 22px;' + 
				'height: 22px;' + 
				'cursor: pointer;' + 
				'border: 1px solid #fff;' + 
				'border-radius: 15%;' + 
				'background-color: #fff;' + 
			'}';
	wCss	+=	'.cmanCLD_CSS_btm:hover {' + 
				'border: 1px solid #ccc;' + 
				'background-color: #eee;' + 
				'box-shadow: none;' + 
			'}';
	wCss	+=	'.cmanCLD_CSS_bty {' + 
				'margin: 2px auto 2px 0;' + 
				'width: 22px;' + 
				'height: 11px;' + 
				'cursor: pointer;' + 
				'border: 1px solid #fff;' + 
				'border-radius: 15%;' + 
				'background-color: #fff;' + 
			'}';
	wCss	+=	'.cmanCLD_CSS_bty:hover {' + 
				'border: 1px solid #ccc;' + 
				'background-color: #eee;' + 
				'box-shadow: none;' + 
			'}';
	wCss	+=	'.cmanCLD_CSS_mstr{' + 
				'font-size: 120%;' + 
				'font-weight :bold;' + 
			'}';
	wCss	+=	'.cmanCLD_CSS_StrOn{' + 
				'color: #333;' + 
			'}';
	wCss	+=	'.cmanCLD_CSS_StrOff{' + 
				'color: #999;' + 
			'}';
	wCss	+=	'</style>';
	// ----- HTML定義 -----------------------------------------------
  var wHtml =	'';
	// ----- カレンダー枠 ---------------------------------------------
  wHtml +='<div id="cmanCLD_ID_area">';
	// ----- 上部年月 ------------------------------------------------
  wHtml +=	'<div>' +
			'<table id="cmanCLD_ID_ym">' +
				'<colgroup span="1" style="width:10%">' +
				'<colgroup span="1" style="width:30%">' +
				'<colgroup span="2" style="width:10%">' +
				'<colgroup span="1" style="width:20%">' +
				'<colgroup span="2" style="width:10%">' +
				'<tr>' +
					'<td>' +
						'<div class="cmanCLD_CSS_btm" onclick="cmanCLD_JS_res(\'y\',\'d\')">' +
							'<svg width="20px" height="20px" viewBox="0 0 22 22">' +
								'<polygon points="14,4 14,18 7,11" style="fill:#999;stroke:none;stroke-width:1">' +
							'</svg>' +
						'</div>' +
					'<  d>' +
					'<td>' +
						'<div class="cmanCLD_CSS_mstr" style="text-align: center;" id="cmanCLD_ID_outy">YYYY年</div>' +
					'<  d>' +
					'<td>' +
						'<div class="cmanCLD_CSS_btm" onclick="cmanCLD_JS_res(\'y\',\'u\')">' +
							'<svg width="20px" height="20px" viewBox="0 0 22 22">' +
								'<polygon points="9,4 9,18 16,11" style="fill:#999;stroke:none;stroke-width:1">' +
							'</svg>' +
						'</div>' +
					'<  d>' +
					'<td>' +
						'<div class="cmanCLD_CSS_btm" style="margin-left:auto;margin-right:2px;" onclick="cmanCLD_JS_res(\'m\',\'d\')">' +
							'<svg width="20px" height="20px" viewBox="0 0 22 22">' +
								'<polygon points="14,4 14,18 7,11" style="fill:#999;stroke:none;stroke-width:1">' +
							'</svg>' +
						'</div>' +
					'<  d>' +
					'<td>' +
						'<div class="cmanCLD_CSS_mstr" style="text-align: center;" id="cmanCLD_ID_outm">MM月</div>' +
					'<  d>' +
					'<td>' +
						'<div class="cmanCLD_CSS_btm" style="margin-left:2px;margin-right:auto;" onclick="cmanCLD_JS_res(\'m\',\'u\')">' +
							'<svg width="20px" height="20px" viewBox="0 0 22 22">' +
								'<polygon points="9,4 9,18 16,11" style="fill:#999;stroke:none;stroke-width:1">' +
							'</svg>' +
						'</div>' +
					'<  d>' +
					'<td>' +
						'<div class="cmanCLD_CSS_btm" style="margin-left:auto;margin-right:2px;" onclick="cmanCLD_JS_cl()">' +
							'<svg width="20px" height="20px" viewBox="0 0 22 22">' +
								'<path stroke="#999" stroke-width="2" fill="none" d="M 7 7 L 16 16  M 7 16 L 16 7">' +
							'</svg>' +
						'</div>' +
					'<  d>' +
				'<  r>' +
			'<  able>' +
			'</div>';
	// ----- 日付 ---------------------------------------------------
	wHtml +=	'<div id="cmanCLD_ID_dateList">' +
			'</div>';
	wHtml +=	'<div style="margin:3px 0 0 auto;text-align: center;font-size: 8pt;padding: 2px 5px;color:#999;background-color:#f3f3f3">' +
				'calendar : ' +
				'<a href="http://web-designer.cman.jp/javascript_ref/" target="_blank" style="color:#999;font-weight:normal;">web-designer.cman.jp</a>' +
			'</div>';
	wHtml +='</div>';
	// ----- 表示枠の作成＆割り当て（非表示で割り当て） -----------------------
	var wEle = document.createElement("div");   // 新規に要素（タグ）を生成
	wEle.id = cmanCLD_VAR["popId"];
	wEle.style.display = "none";
	wEle.style.position = 'fixed';
	document.body.appendChild(wEle);            // このページ (document.body) の最後に生成した要素を追加
	cmanCLD_VAR["objPop"] = wEle;
	cmanCLD_VAR["objPop"].innerHTML	= wCss + "\n" + wHtml;

	// ----- カレンダー内容を編集 ---------------------------------------
	cmanCLD_JS_edit(argYYYY, argMM);
	// ----- 入力要素の位置・サイズ取得 ----------------------------------
	var wObjValue = cmanCLD_VAR["objValue"].getBoundingClientRect();
	var wValueX = wObjValue.left;
	var wValueY = wObjValue.top;
	var wValueH = wObjValue.height;
	// ----- カレンダーの位置を一旦入力エリアの下に割り当て -------------------
	cmanCLD_VAR["objPop"].style.left	= wValueX + 'px';
	cmanCLD_VAR["objPop"].style.top		= ( wValueY + wValueH ) + 'px';
	// ----- カレンダーを100%透過（見えない状態で）非表示解除 -----------------
	cmanCLD_VAR["objPop"].style.opacity	= 0;
	cmanCLD_VAR["objPop"].style.display	= '';
	// ----- カレンダーの縦サイズを取得 ----------------------------------
	var wObjPop = cmanCLD_VAR["objPop"].getBoundingClientRect();
	var wPopH = wObjPop.height;
	// ----- カレンダーの表示位置設定 -----------------------------------
	// 表示可能域を比較し、優先順位：下＞上で設定
	// 両方とも満たさない場合は下に表示
	var wH = document.documentElement.clientHeight - (wValueY + wValueH);
	if(wH > wPopH){
		cmanCLD_VAR["objPop"].style.top		= (wValueY + wValueH)+'px';
	}
	else if	(wValueY > wPopH){
		cmanCLD_VAR["objPop"].style.top		= (wValueY - wPopH )+'px';
	}
	else{
		cmanCLD_VAR["objPop"].style.top		= (wValueY + wValueH)+'px';
	}
	// ----- カレンダーの透過を解除して表示 -------------------------------
	cmanCLD_VAR["objPop"].style.opacity	= 1;
}
// =========================================================================================
//	日付が選択されたら
// =========================================================================================
function cmanCLD_JS_sel(argYMD){
	// ----- 選択した日付を設定する -------------------------------------
  cmanCLD_VAR["objValue"].value = argYMD;
	cmanCLD_VAR["selDate"]        = argYMD;
	// ----- カレンダーを閉じる -----------------------------------------
  cmanCLD_JS_cl();
}
//======================================================================
//	閉じるボタンが押されたら
//======================================================================
function cmanCLD_JS_cl(){
	// ----- カレンダーが開いていない場合はreturn -------------------------
  if(document.getElementById(cmanCLD_VAR["popId"])){
	}else{
		return;
	}
	// ----- 指定の関数を実行 -----------------------------------------
  var wObjAt = cmanCLD_VAR["objValue"].getAttribute("cmanCLDat").replace(/\s+/g, "").split(",");
	for( var i=0; i<wObjAt.length; i++){
		if(wObjAt[i].substr(0,5).toUpperCase() == "FUNC:"){
			if('selDate' in cmanCLD_VAR){
			}else{
				cmanCLD_VAR["selDate"] = '';
			}
			try{
				eval(wObjAt[i].substr(5)+'("'+cmanCLD_VAR["selDate"]+'")');
			}
			catch(e){
				alert('関数('+wObjAt[i].substr(5)+')を実行できません');
			}
		}
	}
	// ----- 登録したカレンダー要素を消す ---------------------------------
	var wDelElm = document.getElementById(cmanCLD_VAR["popId"]);
	document.body.removeChild(wDelElm);
	// ----- WKハッシュクリア -------------------------------------------
	for(var key in cmanCLD_VAR){
		delete cmanCLD_VAR[key];
	}
}
//======================================================================
//	日付チェック
//======================================================================
function cmanCLD_JS_DateChk(argDate) {
	var wY = 0;
	var wM = 0;
	var wD = 0;
	if(argDate==''){return true;}
	var wYMD = argDate.split("-");
	if(wYMD.length != 3){
		return false;
	}
	if(wYMD[0].toString().match(/^[0-9]+$/)){wY = parseInt(wYMD[0]);}
	if(wYMD[1].toString().match(/^[0-9]+$/)){wM = parseInt(wYMD[1]);}
	if(wYMD[2].toString().match(/^[0-9]+$/)){wD = parseInt(wYMD[2]);}
	if((wY < 1900)||(wM < 1)||(wM > 12)||(wD < 1)||(wD > 31)){
		return false;
	}
	var wDate = new Date(wY, wM - 1, wD, 0, 0, 0, 0);
	if((wDate.getFullYear() != wY)||(wDate.getMonth() != wM - 1)||(wDate.getDate() != wD)){
	        return false;
	}
	return true;
}
//======================================================================
//	日付編集
//======================================================================
function cmanCLD_JS_dateEdit(argYear, argMonth, argDate){
	if(argYear == ''){
		return '';
	}
	var wYYYY	= argYear;
	var wMM		= ("0" + argMonth).slice(-2);
	var wDD		= ("0" + argDate).slice(-2);
	var wObjAt = cmanCLD_VAR["objValue"].getAttribute("cmanCLDat").replace(/\s+/g, "");
	if      (wObjAt.match(/FORM:2/i)){return wYYYY + '' + wMM + '' + wDD;}
	else if (wObjAt.match(/FORM:3/i)){return wYYYY + '/' + wMM + '/' + wDD;}
	else                             {return wYYYY + '-' + wMM + '-' + wDD;}
}
```

```javascript:utility.js
function confirm_delete_appli( id ){
  if( window.confirm("申請を削除しますがよろしいですか？")){
    location.href = "/delete/" + id;
  }
}

function getToday(){
  let today = new Date();
  return( 
    today.getFullYear() + '-' 
    + ('0' + (today.getMonth() + 1 ) ).slice( -2 ) + '-'
    + ('0' + today.getDate() ).slice( -2 )
  );
}

function numeric_check(itemobject){
  var flag = 0;
  if(itemobject.value.match(/[^0-9]+/)){
    flag = 1;
  }
  if(flag){
    window.alert('数字以外が入力されています');
    return false;
  }
  else{
    return true;
  }
}
```

```css:style.css
body { margin: 0px; }
h1 { width:800px; background: slategray; color: snow; padding: 2px; }
h2 { margin-left:0px; padding-left:5px; width:780px; background: rgb(219, 219, 219); border-bottom: 1px solid dimgray; }
h3 { margin-left:20px; padding-left:5px; width:680px; background: rgb(239, 236, 239); border-top: 1px solid dimgray; }
a { color: #000; text-decoration: none; background: #ccc; }
th, td { border-collapse: collapse; border-bottom:1px solid dimgray; padding:2px; }
input.submit { width: 180px; font-weight: bold;}
button.menu { width: 250px; height:40px; background: seashell; font-size: 20px; }
.required { background: lemonchiffon; }
div.footer { width: 800px; margin-top: 50px; border-top: dimgray 1px solid; border-bottom: dimgray 1px solid;font-size: 12px; background: rgb(187, 186, 186); color: white; }
.caution { color: red;}
.required { background: lemonchiffon; color:black;}
.new_author { position: relative; left: 200px; }
.author,span { background:dimgray;color: white; }
.backgainsboro { background: gainsboro; }
.backsilver { background: silver; }
.backgray { background: gray; }
.rightalign { text-align: right; }
.centeralign { text-align: center; }
.leftalign { text-align: left; }
.bottomnone { border-bottom:none; }
.width200{ width: 200px;}.width300{width: 300px; }.width500{width: 500px; }
.padding5{padding: 5px;}
.marginleft200 { margin-left: 200px; }
#applicantsdiv { width: 300px; }
```
## srappli-flask/web/templatesフォルダ

### srappli-flask/web/templates/base.html

```html:base.html
<!DOCTYPE html>
<html>
    <head>
        <meta http-equiv="X-UA-Compatible" content="IE=edge"/>
        <meta charset="utf-8" />
        <title>{% block title %}{% endblock %} - 設置申請<  itle>
        
        <link rel="stylesheet" href="{{ url_for('static', filename = 'style.css') }}" />
        <script src="{{ url_for('static', filename = 'calendar.js') }}" charset="utf-8"></script>
        <script src="{{ url_for('static', filename = 'utility.js') }}" charset="utf-8"></script>
        <script>
            window.onload = function() {
                if( document.getElementById('applidate') ){
                    document.getElementById('applidate').value = getToday();
                }
            }
        </script>
    </head>
    <body>
        {% block content %}{% endblock %}
        <div class="footer centeralign">ホゲホゲ本部ファーファー部</div>
    </body>
</html>
```
### srappli-flask/web/templates/index.html

```html:index.html
{% extends 'base.html' %}

{% block title %}サーバールーム設置申請システム{% endblock %}

{% block content %}
  <h1>サーバールーム設置申請システム</h1>

  <h2>申請メニュー</h2>
  <div>
    <h3>設置</h3>
    <a href="{{ url_for('installs.new') }}"><button class="menu">新規設置申請</button></a>
    <a href="{{ url_for('installs.all') }}"><button class="menu">設置申請一覧</button></a>
  </div>
  <h2>管理者メニュー</h2>
  <div>
    <h3>棚</h3>
    <a href="{{ url_for('stragebins.all') }}"><button class="menu">棚番号一覧</button></a>  
    <a href="{{ url_for('stragebins.new') }}"><button class="menu">新規棚番号</button></a>
  </div>
  <div>
    <h3>所属部署</h3>
    <a href="{{ url_for('departments.all') }}"><button class="menu">所属部署一覧</button></a>  
    <a href="{{ url_for('departments.upload') }}"><button class="menu">所属部署アップロード</button></a>
  </div>
  <div>
    <h3>社員</h3>
    <a href="{{ url_for('employees.all') }}"><button class="menu">社員一覧</button></a>  
    <a href="{{ url_for('employees.upload') }}"><button class="menu">社員アップロード</button></a>
  </div>
{% endblock %}
```
## web/templates/installs

### web/templates/installs/all.html

```html:all.html
{% extends 'base.html' %}

{% block title %}サーバー{% endblock %}

{% block content %}
    <h1>設置申請一覧</h1>
    <a href="/"><button>メニューに戻る</button></a>
    <a href="{{ url_for('installs.new') }}"><button>新規設置申請</button></a>
    <a href="{{ url_for('stragebins.all') }}"><button>棚番一覧</button></a>
    <a href="{{ url_for('installs.write') }}"><button>データの書き出し</button></a>
    <table>
        <thead class="backgainsboro">
            <th colspan="2">申請</th><th colspan="3">申請者</th><th colspan="3">コンピュータ</th><th>棚</th>
        </thead>
        <thead>
            <th>ID</th><th>年月日</th><th>社員ID</th><th>所属</th><th>氏名</th><th>台帳No.</th><th>設置希望日</th><th>設置終了予定日</th><th>希望棚番</th>
        </thead>
        <tbody>
            {% for install in installs %}
                <tr>
                    <td>
                        <a href="{{ url_for( 'installs.show', install_id = install['id'] ) }}"><button>{{ install['id'] }}</button></a>
                    </td>
                    <td>{{ install['applidate'] }}</td>
                    <td>{{ install['applicantsid'] }}</td>
                    <td>{{ install['applicantsdiv'] }}</td>
                    <td>{{ install['applicantsname'] }}</td>
                    <td>{{ install['ledgerno'] }}</td>
                    <td>{{ install['hopedate'] }}</td>
                    <td>{{ install['enddate'] }}</td>
                    <td>{{ install['stragebin'] }}</td>
                </tr>
            {% endfor %}
        </tbody>
    </table>
{% endblock %}
```

### web/templates/installs/edit.html

```html:edit.html
{% extends 'base.html' %}

{% block header %}
    <h1>{% block title %}申請Ωを編集{% endblock %}</h1>
{% endblock %}

{% block content %}
    <h2>申請を編集します</h2>

    <div>
        <a href="/"><button>メニューに戻る</button></a>
        <a href="{{ url_for( 'installs.show', install_id = install['id'] ) }}"><button>詳細に戻る</button></a>
        <a href="{{ url_for( 'installs.all' ) }}"><button>申請一覧に戻る</button></a>
    </div>
    <div class="caution">{{ applicantsid_message }}</div>
    <div class="caution">{{ ledgerno_message }}</div>
    <form method="POST">
        <table>
            <thead>
                <th class="rightalign">分類</th><th class="rightalign">申請項目</th><th class="width300 leftalign">申請入力</th>
            </thead>
            <tbody>
                <tr>
                    <td class="rightalign backgainsboro">申請</td>
                    <td class="rightalign">申請日</td>
                    <td><input name="applidate" id="applidate" size="10" class="backsilver" value="{{ install['applidate'] }}" /></td>
                </tr>
                <tr>
                    <td rowspan="3" class="rightalign backgainsboro">申請者</td>
                    <td class="rightalign bottomnone">社員ID(先頭P無し7桁)</td>
                    <td class="bottomnone"><input name="applicantsid" id="applicantsid" size="7" class="required" value="{{ install['applicantsid'] }}" /></td>
                </tr>
                <tr>
                    <td class="rightalign bottomnone">所属部署</td>
                    <td class="bottomnone">
                        <select name="applicantsdiv" id="applicantsdiv">
                            <option value=""></option>
                            {% for department in departments %}
                                {% if (department['id']+'-'+department['abbreviation']) == install['applicantsdiv'] %}
                                    <option value="{{ department['id'] }}-{{ department['abbreviation'] }}" selected>
                                            {{ department['id'] }}-{{ department['abbreviation'] }}
                                    </option>
                                {% else %}
                                    <option value="{{ department['id'] }}-{{ department['abbreviation'] }}">
                                    {{ department['id'] }}-{{ department['abbreviation'] }}
                                    </option>
                                {% endif %}
                            {% endfor %}
                        </select>
                    </td>
                </tr>
                <tr>
                    <td class="rightalign">氏名</td>
                    <td><input name="applicantsname" id="applicantsname" value="{{ install['applicantsname'] }}" /></td>
                </tr>
                <tr>
                    <td rowspan="3" class="rightalign backgainsboro">コンピューター</td>
                    <td class="rightalign bottomnone">台帳No.</td>
                    <td class="bottomnone"><input name="ledgerno" id="ledgerno" size="7" class="required" value="{{ install['ledgerno'] }}" /></td>
                </tr>
                <tr>
                    <td class="rightalign bottomnone">設置希望日</td>
                    <td class="bottomnone"><input name="hopedate" id="hopedate" type="date" cmanCLDat="USE:ON"  class="required" value="{{ install['hopedate'] }}" /></td>
                </tr>
                <tr>
                    <td class="rightalign">設置終了予定日</td>
                    <td><input name="enddate" id="enddate" type="date" cmanCLDat="USE:ON" value="{{ install['enddate'] }}" /></td>
                </tr>
                <tr>
                    <td class="rightalign backgainsboro">棚</td>
                    <td class="rightalign">希望棚番</td>
                    <td>
                        <select name="stragebin" id="stragebin">
                            <option value=""></option>
                            <option value="{{ install['stragebin'] }}" selected>{{ install['stragebin'] }}</option>
                            {% for stragebin in stragebins %}
                                <option value="{{ stragebin['cabinetno'] }}-{{ stragebin['columnno'] }}-{{ stragebin['stageno'] }}">
                                {{ stragebin['cabinetno'] }}-{{ stragebin['columnno'] }}-{{ stragebin['stageno'] }}
                                </option>
                            {% endfor %}
                        </select>
                        (キャビネットNO.-列No.-段No.)
                    </td>
                </tr>
            </tbody>
        </table>
        <p><input class="submit marginleft200" type="submit" value="編集確定"></p>
    </form>
    <h3>棚番マップ</h3>
    <img src="./../../static/img/staragebins_map.png" style="width:700px;" />
{% endblock %}
```

### web/templates/installs/new.html

```html:new.html
{% extends 'base.html' %}

{% block header %}
    <h1>{% block title %}新規書籍{% endblock %}</h1>
{% endblock %}

{% block content %}
    <h2>サーバールームに新規サーバーの設置を申請します</h2>
    <div>
        <a href="/"><button>メニューに戻る</button></a>
        <a href="{{ url_for( 'installs.all' ) }}"><button>設置申請一覧に戻る</button></a>
    </div>
    <div class="caution">{{ applicantsid_message }}</div>
    <div class="caution">{{ ledgerno_message }}</div>
    <form method="POST">
        <table>
            <thead>
                <th class="rightalign">分類</th><th class="rightalign">申請項目</th><th class="width300 leftalign">申請入力</th>
            </thead>
            <tbody>
                <tr>
                    <td class="rightalign backgainsboro">申請</td>
                    <td class="rightalign">申請日</td>
                    <td><input name="applidate" id="applidate" size="10"  type="date" cmanCLDat="USE:ON"  class="backsilver" /></td>
                </tr>
                <tr>
                    <td rowspan="3" class="rightalign backgainsboro">申請者</td>
                    <td class="rightalign bottomnone">社員ID(先頭P無し7桁)</td>
                    <td class="bottomnone"><input name="applicantsid" id="applicantsid" size="7" class="required" /></td>
                </tr>
                <tr>
                    <td class="rightalign bottomnone">所属部署</td>
                    <td class="bottomnone">
                        <select name="applicantsdiv" id="applicantsdiv">
                            <option value=""></option>
                            {% for department in departments %}
                                <option value="{{ department['id'] }}-{{ department['abbreviation'] }}">
                                    {{ department['id'] }}-{{ department['abbreviation'] }}
                                </option>
                            {% endfor %}
                        </select>
                    </td>
                </tr>
                <tr>
                    <td class="rightalign">氏名</td>
                    <td><input name="applicantsname" id="applicantsname" /></td>
                </tr>
                <tr>
                    <td rowspan="3" class="rightalign backgainsboro">コンピューター</td>
                    <td class="rightalign bottomnone">台帳No.</td>
                    <td class="bottomnone"><input name="ledgerno" id="ledgerno" size="7" class="required" /></td>
                </tr>
                <tr>
                    <td class="rightalign bottomnone">設置希望日</td>
                    <td class="bottomnone"><input name="hopedate" id="hopedate" type="date" cmanCLDat="USE:ON" class="required" /></td>
                </tr>
                <tr>
                    <td class="rightalign">設置終了予定日</td>
                    <td><input name="enddate" id="enddate" type="date" cmanCLDat="USE:ON" /></td>
                </tr>
                <tr>
                    <td class="rightalign backgainsboro">棚</td>
                    <td class="rightalign">希望棚番</td>
                    <td>
                        <select name="stragebin" id="stragebin" class="required">
                            <option value=""></option>
                            {% for stragebin in stragebins %}
                                <option value="{{ stragebin['cabinetno'] }}-{{ stragebin['columnno'] }}-{{ stragebin['stageno'] }}">
                                    {{ stragebin['cabinetno'] }}-{{ stragebin['columnno'] }}-{{ stragebin['stageno'] }}
                                </option>
                            {% endfor %}
                        </select>
                        (キャビネットNO.-列No.-段No.)
                    </td>
                </tr>
            </tbody>
        </table>
        ※<span class="required">黄色背景色の項目</span>は必須入力です
        <p><input class="submit marginleft200" type="submit" value="申請"></p>
    </form>
    <h3>棚番マップ</h3>
    <img src="../static/img/staragebins_map.png" style="width:700px;" />
{% endblock %}
```

```html:show.html
{% extends 'base.html' %}

{% block title %}設置申請の詳細{% endblock %}

{% block content %}
    <h2>申請ID：{{ install['id'] }}　設置申請の詳細</h2>
    <div>
        <a href="/"><button>メニューに戻る</button></a>
        <a href="{{ url_for( 'installs.all' ) }}"><button>設置申請一覧に戻る</button></a>
        <a href="{{ url_for( 'installs.edit', install_id = install['id'] ) }}"><button>申請を編集</button></a>
        <a href="{{ url_for( 'installs.delete', install_id = install['id'] ) }}"><button>申請を削除</button></a>
    </div>
    <table>
        <thead>
            <th class="rightalign">分類<  h><th class="rightalign">申請項目<  h><th class="width300 leftalign">申請内容<  h>
        <  head>
        <tbody>
            <tr>
                <td class="rightalign backgainsboro">申請<  d>
                <td class="rightalign">申請日<  d>
                <td>{{ install['applidate'] }}<  d>
            <  r>
            <tr>
                <td rowspan="3" class="rightalign backgainsboro">申請者<  d>
                <td class="rightalign bottomnone">社員ID<  d>
                <td class="bottomnone">{{ install['applicantsid'] }}<  d>
            <  r>
            <tr>
                <td class="rightalign bottomnone">所属<  d>
                <td class="bottomnone">{{ install['applicantsdiv'] }}<  d>
            <  r>
            <tr>
                <td class="rightalign">氏名<  d>
                <td>{{ install['applicantsname'] }}<  d>
            <  r>
            <tr>
                <td rowspan="3" class="rightalign backgainsboro">コンピューター<  d>
                <td class="rightalign bottomnone">台帳No.<  d>
                <td class="bottomnone">{{ install['ledgerno'] }}<  d>
            <  r>
            <tr>
                <td class="rightalign bottomnone">設置希望日<  d>
                <td class="bottomnone">{{ install['hopedate'] }}<  d>
            <  r>
            <tr>
                <td class="rightalign">設置終了予定日<  d>
                <td>{{ install['enddate'] }}<  d>
            <  r>
            <tr>
                <td class="rightalign backgainsboro">棚<  d>
                <td class="rightalign">希望棚番<  d>
                <td>{{ install['stragebin'] }}<  d>
            <  r>
        <  body>
    <  able>
{% endblock %}
```
```html:upload.html
{% extends 'base.html' %}

{% block title %}画像をアップロード{% endblock %}

{% block content %}
    <h2>  「{{ install['title'] }}」の画像を指定</h2>
    <form method="POST" enctype="multipart/form-data">
        <div>
            ファイルをアップロードしてください<br/>
            <input type="file" name="file" />
        </div>
        <input type="submit" value="アップロード" />
    </form>
    <div>
        <a href="{{ url_for('installs.show', install_id=install['id']) }}">
            アップロードをやめる
        </a>
    </div>
{% endblock %}
```
```html:write.html
{% extends 'base.html' %}

{% block title %}データの書き出し{% endblock %}
{% block content %}
    <h1>一覧のCSV形式</h1>
    <div>
        <a href="{{ url_for( 'static' , filename='csv/installs.csv') }}" download="installs.csv">
            ダウンロード
        </a> | 
        <a href="{{ url_for( 'installs.all' ) }}">一覧に戻る</a>
    </div>
    <textarea rows="10" cols="50">{{ str }}<  extarea>
{% endblock %}
```
##### srappli-flask/web  emplates/stragebinsフォルダ
```html:all.html
{% extends 'base.html' %}

{% block title %}棚番号{% endblock %}

{% block content %}
    <h1>棚番一覧</h1>
    <a href="/"><button>メニューに戻る</button></a>
    <a href="{{ url_for('stragebins.new') }}"><button>新規棚番号</button></a>
    <a href="{{ url_for('installs.all') }}"><button>設置申請一覧</button></a>
    <a href="{{ url_for('stragebins.upload') }}"><button>CSVファイルから棚番号データを追加</button></a>
    <table>
        <thead>
            <th>ID<  h><th>棚番号<  h><th>キャビネットNo.<  h><th>棚段No.<  h><th>列No.<  h>
        <  head>
        <tbody>
            {% for stragebin in stragebins %}
                <tr>
                <td>{{ stragebin['id'] }}<td>
                    <a href="{{ url_for( 'stragebins.show', stragebin_id = stragebin['id'] ) }}">
                            <button>{{ stragebin['cabinetno'] }} - {{ stragebin['binno'] }} - {{ stragebin['seqno'] }}</button>
                    </a>
                <  d>
                <td class="centeralign">{{ stragebin['cabinetno'] }}<  d>
                <td class="centeralign">{{ stragebin['binno'] }}<  d>
                <td class="centeralign">{{ stragebin['seqno'] }}<  d>
            <  r>
        {% endfor %}
        <  body>
    <  able>
{% endblock %}
```
```html:edit.html
{% extends 'base.html' %}

{% block header %}
    <h1>{% block title %}棚番号を編集{% endblock %}</h1>
{% endblock %}

{% block content %}
    <h2>ID：{{ stragebin['id'] }} の棚番号を編集します</h2>
    <div>
        <a href="/"><button>メニューに戻る</button></a>
        <a href="{{ url_for( 'stragebins.show', stragebin_id = stragebin['id'] ) }}"><button>詳細に戻る</button></a>
        <a href="{{ url_for( 'stragebins.all' ) }}"><button>棚番一覧に戻る</button></a>
    </div>
    
    <form method="POST">
        <table>
            <thead>
                <th>項目<  h><th>番号<  h>
            <  head>
            <tbody>
                <tr>
                    <td class="backgainsboro">キャビネット番号<  d>
                    <td class="centeralign">
                        <select name="cabinetno" id="cabinetno">
                            {% for cabinetno in range(1,7) %}
                                {% if cabinetno == stragebin['cabinetno'] %}
                                    <option value="{{ cabinetno }}" selected>{{ cabinetno }}</option>
                                {% else %}
                                    <option value="{{ cabinetno }}">{{ cabinetno }}</option>
                                {% endif %}
                            {% endfor%}
                        </select>
                    <  d>
                <  r>
                <tr>
                    <td class="backgainsboro">段番号<  d>
                    <td class="centeralign">
                        <select name="binno" id="binno">
                            {% for binno in range(1,4) %}
                                {% if binno == stragebin['binno'] %}
                                    <option value="{{ binno }}" selected>{{ binno }}</option>
                                {% else %}
                                    <option value="{{ binno }}">{{ binno }}</option>
                                {% endif %}
                            {% endfor%}
                        </select>
                    <  d>
                <  r>
                <tr>
                    <td class="backgainsboro">位置番号<  d>
                    <td class="centeralign">
                        <select name="seqno" id="seqno">
                            {% for seqno in range(1,4) %}
                                {% if seqno == stragebin['seqno'] %}
                                    <option value="{{ seqno }}" selected>{{ seqno }}</option>
                                {% else %}
                                    <option value="{{ seqno }}">{{ seqno }}</option>
                                {% endif %}
                            {% endfor %}
                        </select>
                    <  d>
                <  r>
            <  body>
        <  able>
            
        <p><input type="submit" value="登録" class="submit"/></p>
    </form>
{% endblock %}
```

```html:new.html
{% extends 'base.html' %}

{% block header %}
    <h1>{% block title %}新規棚番号{% endblock %}</h1>
{% endblock %}

{% block content %}
    <h2>棚番号を追加します</h2>
    <div>
        <a href="/"><button>メニューに戻る</button></a>
        <a href="{{ url_for( 'stragebins.all' ) }}"><button>棚番号一覧に戻る</button></a>
    </div>
    <form method="POST">
        <table>
            <thead>
                <th>項目<  h><th>番号<  h>
            <  head>
            <tbody>
                <tr>
                    <td class="backgainsboro">キャビネット番号<  d>
                    <td class="centeralign">
                        <select name="cabinetno" id="cabinetno">
                            <option value=""></option>
                            {% for cabinetno in range(1,7) %}
                                <option value="{{ cabinetno }}">{{ cabinetno }}</option>
                            {% endfor%}
                        </select>
                    <  d>
                <  r>
                <tr>
                    <td class="backgainsboro">段番号<  d>
                    <td class="centeralign">
                        <select name="binno" id="binno">
                            <option value=""></option>
                            {% for binno in range(1,4) %}
                                <option value="{{ binno }}">{{ binno }}</option>
                            {% endfor%}
                        </select>
                    <  d>
                <  r>
                <tr>
                    <td class="backgainsboro">位置番号<  d>
                    <td class="centeralign">
                        <select name="seqno" id="seqno">
                            <option value=""></option>
                            {% for seqno in range(1,4) %}
                                <option value="{{ seqno }}">{{ seqno }}</option>
                            {% endfor %}
                        </select>
                    <  d>
                <  r>
            <  body>
        <  able>
        <p><input type="submit" value="登録" class="submit" /></p>
    </form>
{% endblock %}
```

```html:show.html
{% extends 'base.html' %}

{% block title %}棚番号詳細{% endblock %}

{% block content %}
    <h2>
        棚ID：{{ stragebin['id'] }} 
        ( 棚番：
        {{ stragebin['cabinetno'] }} - {{ stragebin['binno'] }} - {{ stragebin['seqno'] }} 
        ) 詳細
    </h2>
    <div>
s        <a href="{{ url_for( 'stragebins.edit', stragebin_id = stragebin['id']) }}"><button>編集</button></a>
        <a href="{{ url_for( 'stragebins.delete', stragebin_id = stragebin['id'] ) }}"><button>データを削除</button></a>
    </div>
    <table>
        <thead>
            <th>項目<  h><th>番号<  h>
        <  head>
        <tbody>
            <tr>
                <td class="backgainsboro">ID番号<  d>
                <td class="centeralign">{{ stragebin['id'] }}<  d>
            <  r>
            <tr>
                <td class="backgainsboro">キャビネット番号<  d>
                <td class="centeralign">{{ stragebin['cabinetno'] }}<  d>
            <  r>
            <tr>
                <td class="backgainsboro">段番号<  d>
                <td class="centeralign">{{ stragebin['binno'] }}<  d>
            <  r>
            <tr>
                <td class="backgainsboro">位置番号<  d>
                <td class="centeralign">{{ stragebin['seqno'] }}<  d>
            <  r>
        <  body>
    <  able>
{% endblock %}
```

```html:upload.html
{% extends 'base.html' %}

{% block title %}棚番号データをアップロード{% endblock %}

{% block content %}
    <h2>棚番号データをCSVで読みこませる</h2>
    <form method="POST", enctype="multipart/form-data">
        <div>ファイルをアップロードしてください</div>
        <input type="file" name="file" />
        <input type="submit" value="アップロード" />
    </form>
    <div>
        <a href="{{ url_for('stragebins.all') }}">アップロードをやめる</a>
    </div>
{% endblock %}
```
## DB作成
```bash:bash(macOS,Linux)
$ cd instance
$ python create_installdb.py
$ python insert_installdb.py
$ insert_stragebintable.py
$ cd ..
```

## Webアプリ起動

```bash:bash(macOS,Linux)
$ export FLASK_ENV="development"
$ export FLASK_APP="web"
$ flask run --host='0.0.0.0' --port=5000
```

```powershell:powershell(WindowsServer2016)
> cd c:\Dev\srappli-flask\
> $env:FLASK_ENV="development"
> $env:FLASK_APP="web"
> flask run --host='0.0.0.0' --port=5000
```

## Webアプリ実行

URL　[http://SaverName:5000/](http://SaverName:5000/)　にWebブラウザでアクセスする
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/124810/5302d3ff-53a4-b709-5802-2dcce57b538f.png)