Compare commits

...

No commits in common. "main" and "d1d662f1b06e4ca7696434660afe31abf9804114" have entirely different histories.

8628 changed files with 758606 additions and 3 deletions

63
.gitattributes vendored Normal file
View File

@ -0,0 +1,63 @@
###############################################################################
# Set default behavior to automatically normalize line endings.
###############################################################################
* text=auto
###############################################################################
# Set default behavior for command prompt diff.
#
# This is need for earlier builds of msysgit that does not have it on by
# default for csharp files.
# Note: This is only used by command line
###############################################################################
#*.cs diff=csharp
###############################################################################
# Set the merge driver for project and solution files
#
# Merging from the command prompt will add diff markers to the files if there
# are conflicts (Merging from VS is not affected by the settings below, in VS
# the diff markers are never inserted). Diff markers may cause the following
# file extensions to fail to load in VS. An alternative would be to treat
# these files as binary and thus will always conflict and require user
# intervention with every merge. To do so, just uncomment the entries below
###############################################################################
#*.sln merge=binary
#*.csproj merge=binary
#*.vbproj merge=binary
#*.vcxproj merge=binary
#*.vcproj merge=binary
#*.dbproj merge=binary
#*.fsproj merge=binary
#*.lsproj merge=binary
#*.wixproj merge=binary
#*.modelproj merge=binary
#*.sqlproj merge=binary
#*.wwaproj merge=binary
###############################################################################
# behavior for image files
#
# image files are treated as binary by default.
###############################################################################
#*.jpg binary
#*.png binary
#*.gif binary
###############################################################################
# diff behavior for common document formats
#
# Convert binary document formats to text before diffing them. This feature
# is only available from the command line. Turn it on by uncommenting the
# entries below.
###############################################################################
#*.doc diff=astextplain
#*.DOC diff=astextplain
#*.docx diff=astextplain
#*.DOCX diff=astextplain
#*.dot diff=astextplain
#*.DOT diff=astextplain
#*.pdf diff=astextplain
#*.PDF diff=astextplain
#*.rtf diff=astextplain
#*.RTF diff=astextplain

363
.gitignore vendored Normal file
View File

@ -0,0 +1,363 @@
## Ignore Visual Studio temporary files, build results, and
## files generated by popular Visual Studio add-ons.
##
## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore
# User-specific files
*.rsuser
*.suo
*.user
*.userosscache
*.sln.docstates
# User-specific files (MonoDevelop/Xamarin Studio)
*.userprefs
# Mono auto generated files
mono_crash.*
# Build results
[Dd]ebug/
[Dd]ebugPublic/
[Rr]elease/
[Rr]eleases/
x64/
x86/
[Ww][Ii][Nn]32/
[Aa][Rr][Mm]/
[Aa][Rr][Mm]64/
bld/
[Bb]in/
[Oo]bj/
[Oo]ut/
[Ll]og/
[Ll]ogs/
# Visual Studio 2015/2017 cache/options directory
.vs/
# Uncomment if you have tasks that create the project's static files in wwwroot
#wwwroot/
# Visual Studio 2017 auto generated files
Generated\ Files/
# MSTest test Results
[Tt]est[Rr]esult*/
[Bb]uild[Ll]og.*
# NUnit
*.VisualState.xml
TestResult.xml
nunit-*.xml
# Build Results of an ATL Project
[Dd]ebugPS/
[Rr]eleasePS/
dlldata.c
# Benchmark Results
BenchmarkDotNet.Artifacts/
# .NET Core
project.lock.json
project.fragment.lock.json
artifacts/
# ASP.NET Scaffolding
ScaffoldingReadMe.txt
# StyleCop
StyleCopReport.xml
# Files built by Visual Studio
*_i.c
*_p.c
*_h.h
*.ilk
*.meta
*.obj
*.iobj
*.pch
*.pdb
*.ipdb
*.pgc
*.pgd
*.rsp
*.sbr
*.tlb
*.tli
*.tlh
*.tmp
*.tmp_proj
*_wpftmp.csproj
*.log
*.vspscc
*.vssscc
.builds
*.pidb
*.svclog
*.scc
# Chutzpah Test files
_Chutzpah*
# Visual C++ cache files
ipch/
*.aps
*.ncb
*.opendb
*.opensdf
*.sdf
*.cachefile
*.VC.db
*.VC.VC.opendb
# Visual Studio profiler
*.psess
*.vsp
*.vspx
*.sap
# Visual Studio Trace Files
*.e2e
# TFS 2012 Local Workspace
$tf/
# Guidance Automation Toolkit
*.gpState
# ReSharper is a .NET coding add-in
_ReSharper*/
*.[Rr]e[Ss]harper
*.DotSettings.user
# TeamCity is a build add-in
_TeamCity*
# DotCover is a Code Coverage Tool
*.dotCover
# AxoCover is a Code Coverage Tool
.axoCover/*
!.axoCover/settings.json
# Coverlet is a free, cross platform Code Coverage Tool
coverage*.json
coverage*.xml
coverage*.info
# Visual Studio code coverage results
*.coverage
*.coveragexml
# NCrunch
_NCrunch_*
.*crunch*.local.xml
nCrunchTemp_*
# MightyMoose
*.mm.*
AutoTest.Net/
# Web workbench (sass)
.sass-cache/
# Installshield output folder
[Ee]xpress/
# DocProject is a documentation generator add-in
DocProject/buildhelp/
DocProject/Help/*.HxT
DocProject/Help/*.HxC
DocProject/Help/*.hhc
DocProject/Help/*.hhk
DocProject/Help/*.hhp
DocProject/Help/Html2
DocProject/Help/html
# Click-Once directory
publish/
# Publish Web Output
*.[Pp]ublish.xml
*.azurePubxml
# Note: Comment the next line if you want to checkin your web deploy settings,
# but database connection strings (with potential passwords) will be unencrypted
*.pubxml
*.publishproj
# Microsoft Azure Web App publish settings. Comment the next line if you want to
# checkin your Azure Web App publish settings, but sensitive information contained
# in these scripts will be unencrypted
PublishScripts/
# NuGet Packages
*.nupkg
# NuGet Symbol Packages
*.snupkg
# The packages folder can be ignored because of Package Restore
**/[Pp]ackages/*
# except build/, which is used as an MSBuild target.
!**/[Pp]ackages/build/
# Uncomment if necessary however generally it will be regenerated when needed
#!**/[Pp]ackages/repositories.config
# NuGet v3's project.json files produces more ignorable files
*.nuget.props
*.nuget.targets
# Microsoft Azure Build Output
csx/
*.build.csdef
# Microsoft Azure Emulator
ecf/
rcf/
# Windows Store app package directories and files
AppPackages/
BundleArtifacts/
Package.StoreAssociation.xml
_pkginfo.txt
*.appx
*.appxbundle
*.appxupload
# Visual Studio cache files
# files ending in .cache can be ignored
*.[Cc]ache
# but keep track of directories ending in .cache
!?*.[Cc]ache/
# Others
ClientBin/
~$*
*~
*.dbmdl
*.dbproj.schemaview
*.jfm
*.pfx
*.publishsettings
orleans.codegen.cs
# Including strong name files can present a security risk
# (https://github.com/github/gitignore/pull/2483#issue-259490424)
#*.snk
# Since there are multiple workflows, uncomment next line to ignore bower_components
# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622)
#bower_components/
# RIA/Silverlight projects
Generated_Code/
# Backup & report files from converting an old project file
# to a newer Visual Studio version. Backup files are not needed,
# because we have git ;-)
_UpgradeReport_Files/
Backup*/
UpgradeLog*.XML
UpgradeLog*.htm
ServiceFabricBackup/
*.rptproj.bak
# SQL Server files
*.mdf
*.ldf
*.ndf
# Business Intelligence projects
*.rdl.data
*.bim.layout
*.bim_*.settings
*.rptproj.rsuser
*- [Bb]ackup.rdl
*- [Bb]ackup ([0-9]).rdl
*- [Bb]ackup ([0-9][0-9]).rdl
# Microsoft Fakes
FakesAssemblies/
# GhostDoc plugin setting file
*.GhostDoc.xml
# Node.js Tools for Visual Studio
.ntvs_analysis.dat
node_modules/
# Visual Studio 6 build log
*.plg
# Visual Studio 6 workspace options file
*.opt
# Visual Studio 6 auto-generated workspace file (contains which files were open etc.)
*.vbw
# Visual Studio LightSwitch build output
**/*.HTMLClient/GeneratedArtifacts
**/*.DesktopClient/GeneratedArtifacts
**/*.DesktopClient/ModelManifest.xml
**/*.Server/GeneratedArtifacts
**/*.Server/ModelManifest.xml
_Pvt_Extensions
# Paket dependency manager
.paket/paket.exe
paket-files/
# FAKE - F# Make
.fake/
# CodeRush personal settings
.cr/personal
# Python Tools for Visual Studio (PTVS)
__pycache__/
*.pyc
# Cake - Uncomment if you are using it
# tools/**
# !tools/packages.config
# Tabs Studio
*.tss
# Telerik's JustMock configuration file
*.jmconfig
# BizTalk build output
*.btp.cs
*.btm.cs
*.odx.cs
*.xsd.cs
# OpenCover UI analysis results
OpenCover/
# Azure Stream Analytics local run output
ASALocalRun/
# MSBuild Binary and Structured Log
*.binlog
# NVidia Nsight GPU debugger configuration file
*.nvuser
# MFractors (Xamarin productivity tool) working folder
.mfractor/
# Local History for Visual Studio
.localhistory/
# BeatPulse healthcheck temp database
healthchecksdb
# Backup folder for Package Reference Convert tool in Visual Studio 2017
MigrationBackup/
# Ionide (cross platform F# VS Code tools) working folder
.ionide/
# Fody - auto-generated XML schema
FodyWeavers.xsd

View File

@ -0,0 +1,740 @@
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using static DbTableClass;
using static resultClass;
using System.Data.SqlClient;
using Dapper.Contrib.Extensions;
using Dapper;
using Newtonsoft.Json;
namespace QuotationMaker.Controllers
{
[Route("AuthApi")]
public class AuthApiController : ControllerBase
{
private readonly IHttpContextAccessor _httpContextAccessor;
DbConn dbConn = new DbConn();
SqlConnection conn = new SqlConnection(GlobalClass.appsettings("ConnectionStrings:SQLConnectionString"));
SqlConnection elabConn = new SqlConnection(GlobalClass.appsettings("ConnectionStrings:ElabConnectionString"));
public AuthApiController(IHttpContextAccessor httpContextAccessor)
{
this._httpContextAccessor = httpContextAccessor;
}
[Route("deptList")]
public ActionResult DeptList(IFormCollection obj)
{
deptListResult ret = new deptListResult();
authToken token = new authToken(this._httpContextAccessor);
if (token.user_isLogin == false)
{
HttpContext.Response.Cookies.Delete("token_key");
ret.ret = "no";
ret.err_code = "99999";
ret.message = "非登入狀態!";
return Content(JsonConvert.SerializeObject(ret), "application/json;charset=utf-8");
}
if (token.user_perm != "system")
{
ret.ret = "no";
ret.err_code = "90001";
ret.message = "此帳號無此api使用權限!";
return Content(JsonConvert.SerializeObject(ret), "application/json;charset=utf-8");
}
ret.depts = conn.Query<depts>("select * from depts order by dept_order ").ToList();
ret.ret = "yes";
return Content(JsonConvert.SerializeObject(ret), "application/json;charset=utf-8");
}
[Route("groupList")]
public ActionResult GroupList(IFormCollection obj)
{
groupListResult ret = new groupListResult();
authToken token = new authToken(this._httpContextAccessor);
if (token.user_isLogin == false)
{
HttpContext.Response.Cookies.Delete("token_key");
ret.ret = "no";
ret.err_code = "99999";
ret.message = "非登入狀態!";
return Content(JsonConvert.SerializeObject(ret), "application/json;charset=utf-8");
}
if (token.user_perm != "system")
{
ret.ret = "no";
ret.err_code = "90001";
ret.message = "此帳號無此api使用權限!";
return Content(JsonConvert.SerializeObject(ret), "application/json;charset=utf-8");
}
return Content(JsonConvert.SerializeObject(ret), "application/json;charset=utf-8");
}
[Route("addEditGetUser")]
public ActionResult AddEditGetUser(IFormCollection obj)
{
updateUserResult ret = new updateUserResult();
authToken token = new authToken(this._httpContextAccessor);
if (token.user_isLogin == false)
{
HttpContext.Response.Cookies.Delete("token_key");
ret.ret = "no";
ret.err_code = "99999";
ret.message = "非登入狀態!";
return Content(JsonConvert.SerializeObject(ret), "application/json;charset=utf-8");
}
if (token.user_perm != "system")
{
ret.ret = "no";
ret.err_code = "90001";
ret.message = "此帳號無此api使用權限!";
return Content(JsonConvert.SerializeObject(ret), "application/json;charset=utf-8");
}
string method = obj["method"].ToString();
if (method == "")
{
ret.ret = "no";
ret.err_code = "0001";
ret.message = "沒有method參數";
return Content(JsonConvert.SerializeObject(ret), "application/json;charset=utf-8");
}
if (method == "add")
{
string user_type = obj["user_type"].ToString();
string user_perm = obj["user_perm"].ToString();
string user_depts = obj["user_depts"].ToString().Trim(',');
string[] depts = user_depts.Split(",");
if (depts.Length == 0) {
ret.ret = "no";
ret.err_code = "0002";
ret.message = "沒有所屬單位";
return Content(JsonConvert.SerializeObject(ret), "application/json;charset=utf-8");
}
if (user_type == "")
{
ret.ret = "no";
ret.err_code = "0002";
ret.message = "沒有user_type參數";
return Content(JsonConvert.SerializeObject(ret), "application/json;charset=utf-8");
}
//N為E白板帳號
if (user_type == "N")
{
string user_id = obj["user_elabName"].ToString();
user newUser = conn.QueryFirstOrDefault<user>("select * from users where user_id = @user_id ", new { user_id = user_id });
if (newUser != null)
{
ret.ret = "no";
ret.err_code = "0003";
ret.message = "此帳號已經存在於系統!";
return Content(JsonConvert.SerializeObject(ret), "application/json;charset=utf-8");
}
new_userdata elabUser;
try
{
elabUser = elabConn.QueryFirstOrDefault<new_userdata>("select * from new_userdata where userid = @user_id", new { user_id = user_id });
}
catch (Exception ex)
{
ret.ret = "no";
ret.err_code = "90001";
ret.message = ex.Message;
return Content(JsonConvert.SerializeObject(ret), "application/json;charset=utf-8");
}
if (elabUser == null)
{
ret.ret = "no";
ret.err_code = "0004";
ret.message = "E白板無此帳號!";
return Content(JsonConvert.SerializeObject(ret), "application/json;charset=utf-8");
}
string user_uid = GlobalClass.CreateRandomCode(12);
newUser = new user();
newUser.user_uid = user_uid;
newUser.user_name = elabUser.username;
newUser.user_id = elabUser.userid;
newUser.user_email = elabUser.mail;
newUser.user_type = user_type;
newUser.user_onjob = "Y";
newUser.user_perm = user_perm;
newUser.user_ishidden = "N";
newUser.user_createdate = DateTime.Now;
if (user_perm == "")
{
ret.ret = "no";
ret.err_code = "0009";
ret.message = "無此帳號的權限設定值!";
return Content(JsonConvert.SerializeObject(ret), "application/json;charset=utf-8");
}
conn.Insert(newUser);
foreach (string dept_uid in depts) {
if (dept_uid != "")
{
userDept objUserDept = new userDept();
objUserDept.user_uid = user_uid;
objUserDept.dept_uid = dept_uid;
conn.Insert<userDept>(objUserDept);
}
}
ret.ret = "yes";
ret.user = new userWithDept(newUser);
}
else
{
string user_id = obj["user_id"].ToString();
string user_pwd = obj["user_pwd"].ToString();
string user_uid = GlobalClass.CreateRandomCode(12);
string user_name = obj["user_name"].ToString();
string user_email = obj["user_email"].ToString();
if (user_id == "")
{
ret.ret = "no";
ret.err_code = "0006";
ret.message = "請輸入帳號ID!";
return Content(JsonConvert.SerializeObject(ret), "application/json;charset=utf-8");
}
if (user_name == "")
{
ret.ret = "no";
ret.err_code = "0006";
ret.message = "請輸入帳號名稱!";
return Content(JsonConvert.SerializeObject(ret), "application/json;charset=utf-8");
}
if (user_perm == "")
{
ret.ret = "no";
ret.err_code = "0009";
ret.message = "無此帳號的權限設定值!";
return Content(JsonConvert.SerializeObject(ret), "application/json;charset=utf-8");
}
if (GlobalClass.isEmail(user_email) == false)
{
ret.ret = "no";
ret.err_code = "0007";
ret.message = "請輸入正確EMail!";
return Content(JsonConvert.SerializeObject(ret), "application/json;charset=utf-8");
}
user newUser = conn.QueryFirstOrDefault<user>("select * from users where user_id = @user_id ", new { user_id = user_id });
if (newUser != null)
{
ret.ret = "no";
ret.err_code = "0003";
ret.message = "此帳號已經存在於系統!";
return Content(JsonConvert.SerializeObject(ret), "application/json;charset=utf-8");
}
new_userdata elabUser = elabConn.QueryFirstOrDefault("select * from new_userdata where userid = @user_id", new { user_id = user_id });
if (elabUser != null)
{
ret.ret = "no";
ret.err_code = "0005";
ret.message = "E白板系統內有此帳號ID請換帳號或改以E白板帳號加入!";
return Content(JsonConvert.SerializeObject(ret), "application/json;charset=utf-8");
}
newUser = new user();
newUser.user_uid = user_uid;
newUser.user_id = user_id;
newUser.user_name = user_name;
newUser.user_pwd = user_pwd;
newUser.user_email = user_email;
newUser.user_type = user_type;
newUser.user_onjob = "Y";
newUser.user_perm = user_perm;
newUser.user_ishidden = "N";
newUser.user_createdate = DateTime.Now;
conn.Insert(newUser);
foreach (string dept_uid in depts)
{
if (dept_uid != "")
{
userDept objUserDept = new userDept();
objUserDept.user_uid = user_uid;
objUserDept.dept_uid = dept_uid;
conn.Insert<userDept>(objUserDept);
}
}
ret.ret = "yes";
ret.user = new userWithDept(newUser);
}
return Content(JsonConvert.SerializeObject(ret), "application/json;charset=utf-8");
}
if (method == "edit")
{
string user_type = obj["user_type"].ToString();
string user_uid = obj["user_uid"].ToString();
string user_perm = obj["user_perm"].ToString();
string user_depts = obj["user_depts"].ToString().Trim(',');
string[] depts = user_depts.Split(",");
if (depts.Length == 0)
{
ret.ret = "no";
ret.err_code = "0002";
ret.message = "沒有所屬單位";
return Content(JsonConvert.SerializeObject(ret), "application/json;charset=utf-8");
}
if (user_type == "")
{
ret.ret = "no";
ret.err_code = "0002";
ret.message = "沒有user_type參數";
return Content(JsonConvert.SerializeObject(ret), "application/json;charset=utf-8");
}
if (user_perm == "")
{
ret.ret = "no";
ret.err_code = "0009";
ret.message = "無此帳號的權限設定值!";
return Content(JsonConvert.SerializeObject(ret), "application/json;charset=utf-8");
}
user editUser = conn.QueryFirstOrDefault<user>("select * from users where user_uid = @user_uid and user_type = @user_type", new { user_uid = user_uid, user_type = user_type });
if (editUser == null)
{
ret.ret = "no";
ret.err_code = "0008";
ret.message = "沒有此用戶資料!";
return Content(JsonConvert.SerializeObject(ret), "application/json;charset=utf-8");
}
//N為E白板帳號
if (user_type == "N")
{
editUser.user_perm = user_perm;
}
else
{
string user_pwd = obj["user_pwd"].ToString();
string user_name = obj["user_name"].ToString();
string user_email = obj["user_email"].ToString();
editUser.user_perm = user_perm;
if (user_name == "")
{
ret.ret = "no";
ret.err_code = "0006";
ret.message = "請輸入帳號名稱!";
return Content(JsonConvert.SerializeObject(ret), "application/json;charset=utf-8");
}
if (GlobalClass.isEmail(user_email) == false)
{
ret.ret = "no";
ret.err_code = "0007";
ret.message = "請輸入正確EMail!";
return Content(JsonConvert.SerializeObject(ret), "application/json;charset=utf-8");
}
if (user_pwd != "")
{
editUser.user_pwd = user_pwd;
}
editUser.user_name = user_name;
editUser.user_email = user_email;
}
conn.Update<user>(editUser);
conn.Execute("delete userDept where user_uid = @user_uid", new { user_uid = user_uid});
foreach (string dept_uid in depts)
{
if (dept_uid != "") {
userDept objUserDept = new userDept();
objUserDept.user_uid = user_uid;
objUserDept.dept_uid = dept_uid;
conn.Insert<userDept>(objUserDept);
}
}
ret.ret = "yes";
ret.user = new userWithDept(editUser);
return Content(JsonConvert.SerializeObject(ret), "application/json;charset=utf-8");
}
if (method == "del")
{
string user_uid = obj["user_uid"].ToString();
user editUser = conn.QueryFirstOrDefault<user>("select * from users where user_ishidden = 'N' and user_uid = @user_uid ", new { user_uid = user_uid });
if (editUser == null)
{
ret.ret = "no";
ret.err_code = "0008";
ret.message = "沒有此用戶資料!";
return Content(JsonConvert.SerializeObject(ret), "application/json;charset=utf-8");
}
editUser.user_ishidden = "Y";
conn.Update(editUser);
if (editUser.user_lastlogintime == "")
{
conn.Delete(editUser);
}
ret.ret = "yes";
return Content(JsonConvert.SerializeObject(ret), "application/json;charset=utf-8");
}
if (method == "get")
{
string user_uid = obj["user_uid"].ToString();
user editUser = conn.QueryFirstOrDefault<user>("select * from users where user_ishidden = 'N' and user_uid = @user_uid", new { user_uid = user_uid });
if (editUser == null)
{
ret.ret = "no";
ret.err_code = "0008";
ret.message = "沒有此用戶資料!";
return Content(JsonConvert.SerializeObject(ret), "application/json;charset=utf-8");
}
ret.ret = "yes";
ret.user = new userWithDept(editUser);
return Content(JsonConvert.SerializeObject(ret), "application/json;charset=utf-8");
}
return Content(JsonConvert.SerializeObject(ret), "application/json;charset=utf-8");
}
[Route("elab_UserList")]
public ActionResult Elab_UserList(IFormCollection obj)
{
elabUserListResult ret = new elabUserListResult();
authToken token = new authToken(this._httpContextAccessor);
if (token.user_isLogin == false)
{
HttpContext.Response.Cookies.Delete("token_key");
ret.ret = "no";
ret.err_code = "99999";
ret.message = "非登入狀態!";
return Content(JsonConvert.SerializeObject(ret), "application/json;charset=utf-8");
}
if (token.user_perm != "system")
{
ret.ret = "no";
ret.err_code = "90001";
ret.message = "此帳號無此api使用權限!";
return Content(JsonConvert.SerializeObject(ret), "application/json;charset=utf-8");
}
ret.userList = elabConn.Query<new_userdata>("select * from new_userdata where onjob = 0 order by usersn desc ").ToList();
ret.ret = "yes";
return Content(JsonConvert.SerializeObject(ret), "application/json;charset=utf-8");
}
[Route("userList")]
public ActionResult UserList(IFormCollection obj)
{
userListResult ret = new userListResult();
authToken token = new authToken(this._httpContextAccessor);
if (token.user_isLogin == false)
{
HttpContext.Response.Cookies.Delete("token_key");
ret.ret = "no";
ret.err_code = "99999";
ret.message = "非登入狀態!";
return Content(JsonConvert.SerializeObject(ret), "application/json;charset=utf-8");
}
if (token.user_perm != "system")
{
ret.ret = "no";
ret.err_code = "90001";
ret.message = "此帳號無此api使用權限!";
return Content(JsonConvert.SerializeObject(ret), "application/json;charset=utf-8");
}
ret.userList = conn.Query<user>("select * from users where user_ishidden = 'N' order by user_sn desc").ToList();
ret.ret = "yes";
return Content(JsonConvert.SerializeObject(ret), "application/json;charset=utf-8");
}
[Route("logout")]
public ActionResult Logout()
{
signinResult ret = new signinResult();
authToken _objToken = new authToken(this._httpContextAccessor);
if (_objToken.user_isLogin == true)
{
string token_key = _httpContextAccessor.HttpContext.Request.Cookies["token_key"];
conn.Execute("delete token where token_key = @token_key", new { token_key = token_key });
}
HttpContext.Response.Cookies.Delete("token_key");
ret.ret = "yes";
return Content(JsonConvert.SerializeObject(ret), "application/json;charset=utf-8");
}
[Route("signin")]
public ActionResult Signin(IFormCollection obj)
{
signinResult ret = new signinResult();
string input_ID = obj["id"].ToString();
string input_PWD = obj["pwd"].ToString();
string input_isRemember = obj["remember"].ToString();
string sys_ID = GlobalClass.appsettings("Admin:id");
string sys_PWD = GlobalClass.Sha256(GlobalClass.appsettings("Admin:pwd"));
if (input_ID == "")
{
ret.ret = "no";
ret.err_code = "0001";
ret.message = "帳號或密碼錯誤!";
return Content(JsonConvert.SerializeObject(ret), "application/json;charset=utf-8");
}
//判斷是否為系統預設帳號
if (input_ID == sys_ID)
{
if (input_PWD != sys_PWD)
{
ret.ret = "no";
ret.err_code = "0001";
ret.message = "帳號或密碼錯誤!";
return Content(JsonConvert.SerializeObject(ret), "application/json;charset=utf-8");
}
token adminToken = new token();
int intexpireMin = 20;
if (input_isRemember == "Y")
{
intexpireMin = 60 * 24 * 7;
}
string token_key = GlobalClass.CreateRandomCode(24);
adminToken.user_uid = GlobalClass.appsettings("Admin:uid");
adminToken.user_id = GlobalClass.appsettings("Admin:id");
adminToken.token_isremember = input_isRemember;
adminToken.token_key = token_key;
adminToken.token_createdate = DateTime.Now;
adminToken.token_expireddate = DateTime.Now.AddMinutes(intexpireMin);
conn.Insert<token>(adminToken);
CookieOptions options = new CookieOptions();
options.Secure = true;
options.Expires = DateTime.Now.AddMinutes(intexpireMin);
HttpContext.Response.Cookies.Delete("token_key");
_httpContextAccessor.HttpContext.Response.Cookies.Append("token_key", token_key, options);
ret.ret = "yes";
return Content(JsonConvert.SerializeObject(ret), "application/json;charset=utf-8");
}
else
{
//非系統帳號
user webUser = conn.QueryFirstOrDefault<user>("select * from users where user_ishidden = 'N' and user_id = @user_id", new { user_id = input_ID });
if (webUser == null)
{
ret.ret = "no";
ret.err_code = "0002";
ret.message = "系統無此帳號!";
return Content(JsonConvert.SerializeObject(ret), "application/json;charset=utf-8");
}
if (webUser.user_onjob == "N")
{
ret.ret = "no";
ret.err_code = "0003";
ret.message = "此帳號已經離職,無法登入";
return Content(JsonConvert.SerializeObject(ret), "application/json;charset=utf-8");
}
webUser.user_lastlogintime = DateTime.Now.ToString("yyyy/MM/dd HH:mm:ss");
if (webUser.user_type == "Y")
{
if (input_PWD != webUser.user_pwd)
{
ret.ret = "no";
ret.err_code = "0004";
ret.message = "密碼錯誤!";
return Content(JsonConvert.SerializeObject(ret), "application/json;charset=utf-8");
}
}
else
{
new_userdata elabUser = elabConn.QueryFirstOrDefault<new_userdata>("select * from new_userdata where userid = @userid", new { userid = webUser.user_id });
if (input_PWD != GlobalClass.Sha256(elabUser.userpw))
{
ret.ret = "no";
ret.err_code = "0004";
ret.message = "密碼錯誤!";
return Content(JsonConvert.SerializeObject(ret), "application/json;charset=utf-8");
}
if (elabUser.onjob == 1)
{
webUser.user_onjob = "N";
conn.Update(webUser);
ret.ret = "no";
ret.err_code = "0003";
ret.message = "此帳號已經離職,無法登入";
return Content(JsonConvert.SerializeObject(ret), "application/json;charset=utf-8");
}
}
token userToken = new token();
int intexpireMin = 20;
if (input_isRemember == "Y")
{
intexpireMin = 60 * 24 * 7;
}
string token_key = GlobalClass.CreateRandomCode(24);
userToken.user_uid = webUser.user_uid;
userToken.user_id = input_ID;
userToken.token_isremember = input_isRemember;
userToken.token_key = token_key;
userToken.token_createdate = DateTime.Now;
userToken.token_expireddate = DateTime.Now.AddMinutes(intexpireMin);
conn.Insert<token>(userToken);
conn.Update<user>(webUser);
CookieOptions options = new CookieOptions();
options.Secure = true;
options.Expires = DateTime.Now.AddMinutes(intexpireMin);
HttpContext.Response.Cookies.Delete("token_key");
_httpContextAccessor.HttpContext.Response.Cookies.Append("token_key", token_key, options);
ret.ret = "yes";
return Content(JsonConvert.SerializeObject(ret), "application/json;charset=utf-8");
}
ret.ret = "no";
ret.err_code = "9999";
ret.message = "無參數錯誤";
return Content(JsonConvert.SerializeObject(ret), "application/json;charset=utf-8");
}
public class signinResult
{
public string ret = "no";
public string err_code = "0000";
public string message = "";
}
public class userListResult
{
public string ret = "no";
public string err_code = "0000";
public string message = "";
public List<user> userList = new List<user>();
}
public class elabUserListResult
{
public string ret = "no";
public string err_code = "0000";
public string message = "";
public List<new_userdata> userList = new List<new_userdata>();
}
public class updateUserResult
{
public string ret = "no";
public string err_code = "0000";
public string message = "";
public userWithDept user = new userWithDept();
}
}
}

View File

@ -0,0 +1,78 @@
using Microsoft.AspNetCore.Mvc;
namespace QuotationMaker.Controllers
{
public class HomeController : Controller
{
private readonly ILogger<HomeController> _logger;
private readonly IHttpContextAccessor _httpContextAccessor;
private authToken _objToken;
public HomeController(ILogger<HomeController> logger, IHttpContextAccessor httpContextAccessor)
{
_logger = logger;
this._httpContextAccessor = httpContextAccessor;
this._objToken = new authToken(this._httpContextAccessor);
}
public IActionResult Login()
{
return View();
}
public IActionResult UserList()
{
if (checkToken() == false)
{
HttpContext.Response.Cookies.Delete("token_key");
return Redirect("~/Home/Login");
}
if (this._objToken.user_perm != "system")
{
return Redirect("~/");
}
return View();
}
public IActionResult ProjectList()
{
if (checkToken() == false)
{
HttpContext.Response.Cookies.Delete("token_key");
return Redirect("~/Home/Login");
}
return View();
}
public Boolean checkToken()
{
this._objToken = new authToken(this._httpContextAccessor);
if (this._objToken.user_isLogin == false)
{
HttpContext.Response.Cookies.Delete("token_key");
return false;
}
@ViewData["user_name"] = this._objToken.user_name;
ViewData["user_permtype"] = "一般使用者";
if (this._objToken.user_perm == "system")
{
ViewData["authMenu"] = "display:block;";
ViewData["user_permtype"] = "管理者";
}
else
{
ViewData["authMenu"] = "display:none;";
}
return true;
}
}
}

36
Modals/DbConn.cs Normal file
View File

@ -0,0 +1,36 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using System.Data;
using System.Data.SqlClient;
public class DbConn
{
protected string _connectionString { get; set; }
protected SqlConnection _sqlConnection { get; set; }
public DbConn()
{
this._connectionString = GlobalClass.appsettings("ConnectionStrings:SQLConnectionString");
}
public SqlConnection sqlConnection()
{
this._sqlConnection = new SqlConnection(this._connectionString);
if (this._sqlConnection.State != ConnectionState.Open)
{
this._sqlConnection.Open();
}
return this._sqlConnection;
}
public void closeConn()
{
if (this._sqlConnection.State != ConnectionState.Closed)
{
this._sqlConnection.Close();
this._sqlConnection.Dispose();
}
}
}

142
Modals/DbTableClass.cs Normal file
View File

@ -0,0 +1,142 @@
using System;
using System.Collections.Generic;
using Dapper.Contrib.Extensions;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
public class DbTableClass
{
[Table("userDept")]
public class userDept
{
[JsonIgnore]
[Key]
public int userDept_sn { get; set; }
public string user_uid { get; set; } = "";
public string dept_uid { get; set; } = "";
public DateTime userDept_createdate { get; set; } = DateTime.Now;
}
[Table("depts")]
public class depts
{
[JsonIgnore]
[Key]
public int dept_sn { get; set; }
public string dept_name { get; set; } = "";
public string dept_uid { get; set; } = "";
public string dept_code { get; set; } = "";
public int dept_order { get; set; } = 0;
public DateTime dept_createdate { get; set; } = DateTime.Now;
}
[Table("groupUser")]
public class groupUser
{
[JsonIgnore]
[Key]
public int groupUser_sn { get; set; }
public string groupUser_uid { get; set; } = "";
public string group_uid { get; set; } = "";
public string user_uid { get; set; } = "";
public DateTime groupUser_createdate { get; set; } = DateTime.Now;
}
[Table("group")]
public class group
{
[JsonIgnore]
[Key]
public int group_sn { get; set; }
public string group_uid { get; set; } = "";
public string group_name { get; set; } = "";
public DateTime group_createdate { get; set; } = DateTime.Now;
}
[Table("token")]
public class token
{
[JsonIgnore]
[Key]
public int token_sn { get; set; }
public string token_key { get; set; } = "";
public string user_uid { get; set; } = "";
public string user_id { get; set; } = "";
public string token_isremember { get; set; } = "N";
public DateTime token_createdate { get; set; } = DateTime.Now;
public DateTime token_expireddate { get; set; } = DateTime.Now.AddMinutes(20);
}
[Table("users")]
public class user
{
[JsonIgnore]
[Key]
public int user_sn { get; set; }
public string user_uid { get; set; } = "";
public string user_id { get; set; } = "";
public string user_name { get; set; } = "";
public string user_email { get; set; } = "";
public string user_onjob { get; set; } = "N";
public string user_type { get; set; } = "N";
public string user_pwd { get; set; } = "";
public string user_perm { get; set; } = "user";
public string user_pic { get; set; } = "";
public string user_ishidden { get; set; } = "N";
public DateTime user_createdate { get; set; } = DateTime.Now;
public string user_lastlogintime { get; set; } = "";
}
[Table("new_userdata")]
public class new_userdata
{
[JsonIgnore]
[Key]
public int usersn { get; set; }
public string userid { get; set; } = "";
public string userpw { get; set; } = "";
public string username { get; set; } = "";
public int maincategoryid { get; set; } = 1;
public int subcategoryid { get; set; } = 1;
public int grade { get; set; } = 0;
public string mail { get; set; } = "";
public string mailto { get; set; } = "";
public int onjob { get; set; } = 0;
public int permission { get; set; } = 0;
}
}

223
Modals/GlobalClass.cs Normal file
View File

@ -0,0 +1,223 @@
using System.Security.Cryptography;
using System.Text;
using System.Text.RegularExpressions;
using System.Drawing;
using System.Drawing.Imaging;
using System.Drawing.Drawing2D;
public static class GlobalClass
{
public static IServiceProvider ServiceProvider;
public static bool isURL(string url)
{
return Uri.IsWellFormedUriString(url, UriKind.Absolute);
}
public static string GetIP(this HttpContext context)
{
var ip = context.Request.Headers["X-Forwarded-For"].FirstOrDefault();
if (string.IsNullOrEmpty(ip))
{
ip = context.Connection.RemoteIpAddress.ToString();
}
return ip;
}
public static string CreateRandomCode(int Number)
{
string allChar = "0,1,2,3,4,5,6,7,8,9,A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T,U,V,W,X,Y,Z";
string[] allCharArray = allChar.Split(',');
string randomCode = "";
Random rand = new Random(Guid.NewGuid().GetHashCode());
for (int i = 0; i <= Number - 1; i++)
{
int t = rand.Next(allCharArray.Length);
randomCode += allCharArray[t];
}
return randomCode;
}
public static string CreateUniRandomCode(int Number)
{
string allChar = "2,3,4,5,6,7,8,9,A,B,C,D,E,F,G,H,J,K,M,N,P,Q,R,S,U,V,W,X,Y,Z";
string[] allCharArray = allChar.Split(',');
string randomCode = "";
Random rand = new Random(Guid.NewGuid().GetHashCode());
for (int i = 0; i <= Number - 1; i++)
{
int t = rand.Next(allCharArray.Length);
randomCode += allCharArray[t];
}
return randomCode;
}
public static string ToMD5(this string str)
{
using (var cryptoMD5 = System.Security.Cryptography.MD5.Create())
{
//將字串編碼成 UTF8 位元組陣列
var bytes = Encoding.UTF8.GetBytes(str);
//取得雜湊值位元組陣列
var hash = cryptoMD5.ComputeHash(bytes);
//取得 MD5
var md5 = BitConverter.ToString(hash)
.Replace("-", String.Empty)
.ToLower();
return md5;
}
}
public static string Sha256(this string input)
{
System.Security.Cryptography.SHA256CryptoServiceProvider sha256 = new SHA256CryptoServiceProvider();
Byte[] ByteString = Encoding.ASCII.GetBytes(input);
ByteString = sha256.ComputeHash(ByteString);
string returnString = "";
foreach (Byte bt in ByteString)
{
returnString += bt.ToString("x2");
}
return returnString.ToLower();
}
/// <summary>
/// Creates a SHA256 hash of the specified input.
/// </summary>
/// <param name="input">The input.</param>
/// <returns>A hash.</returns>
public static byte[] Sha256(this byte[] input)
{
if (input == null)
{
return null;
}
using (var sha = SHA256.Create())
{
return sha.ComputeHash(input);
}
}
public static bool isEmail(string email)
{
//Email檢查格式
System.Text.RegularExpressions.Regex EmailExpression = new Regex(@"^([a-zA-Z0-9_\-\.]+)@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.)|(([a-zA-Z0-9\-]+\.)+))([a-zA-Z]{2,4}|[0-9]{1,3})(\]?)$", RegexOptions.Compiled | RegexOptions.Singleline);
try
{
if (string.IsNullOrEmpty(email))
{
return false;
}
else
{
return EmailExpression.IsMatch(email);
}
}
catch (Exception ex)
{
//log.Error(ex.Message);
return false;
}
}
public static string appsettings(string key)
{
var builder = new ConfigurationBuilder()
.SetBasePath(Directory.GetCurrentDirectory())
.AddJsonFile("appsettings.json");
var config = builder.Build();
return config[key];
}
public static Image embedImage(Image watermark, Image targetImg, int x, int y)
{
Image outImg;
using (Graphics g = Graphics.FromImage(targetImg))
{
g.DrawImage(watermark, new Rectangle(x, y, watermark.Width, watermark.Height));
outImg = (Image)targetImg.Clone();
}
return outImg;
}
public static Image resizeImage(Image image, int width, int height)
{
var destinationRect = new Rectangle(0, 0, width, height);
var destinationImage = new Bitmap(width, height);
destinationImage.SetResolution(image.HorizontalResolution, image.VerticalResolution);
using (var graphics = Graphics.FromImage(destinationImage))
{
graphics.CompositingMode = CompositingMode.SourceCopy;
graphics.CompositingQuality = CompositingQuality.HighQuality;
using (var wrapMode = new ImageAttributes())
{
wrapMode.SetWrapMode(WrapMode.TileFlipXY);
graphics.DrawImage(image, destinationRect, 0, 0, image.Width, image.Height, GraphicsUnit.Pixel, wrapMode);
}
}
return (Image)destinationImage;
}
/// <summary>
/// base 64字串格式的圖片轉成Image物件
/// </summary>
/// <param name="base64String"></param>
/// <returns></returns>
public static Image Base64StringToImage(string base64String)
{
// Convert base 64 string to byte[]
byte[] Buffer = Convert.FromBase64String(base64String);
byte[] data = null;
Image oImage = null;
MemoryStream oMemoryStream = null;
Bitmap oBitmap = null;
//建立副本
data = (byte[])Buffer.Clone();
try
{
oMemoryStream = new MemoryStream(data);
//設定資料流位置
oMemoryStream.Position = 0;
oImage = System.Drawing.Image.FromStream(oMemoryStream);
//建立副本
oBitmap = new Bitmap(oImage);
}
catch
{
throw;
}
finally
{
oMemoryStream.Close();
oMemoryStream.Dispose();
oMemoryStream = null;
}
//return oImage;
return oBitmap;
}
public static string ImageToBase64(Image image, System.Drawing.Imaging.ImageFormat format)
{
using (MemoryStream ms = new MemoryStream())
{
// Convert Image to byte[]
image.Save(ms, format);
byte[] imageBytes = ms.ToArray();
// Convert byte[] to base 64 string
string base64String = Convert.ToBase64String(imageBytes);
return base64String;
}
}
}

165
Modals/authToken.cs Normal file
View File

@ -0,0 +1,165 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using Microsoft.AspNetCore.Cors;
using Dapper;
using System.Data;
using System.Data.SqlClient;
using static DbTableClass;
using static resultClass;
using Dapper.Contrib.Extensions;
using System.Reflection.Metadata.Ecma335;
using Microsoft.Extensions.Options;
public class authToken
{
private readonly IHttpContextAccessor _httpContextAccessor;
public string user_uid { get; set; }
public string user_id { get; set; }
public string user_name { get; set; }
public string user_perm { get; set; }
public Boolean user_isLogin { get; set; }
public string error_msg { get; set; }
public HttpRequest myRequest { get; set; }
public authToken(IHttpContextAccessor httpContextAccessor)
{
this._httpContextAccessor = httpContextAccessor;
SqlConnection conn = new SqlConnection(GlobalClass.appsettings("ConnectionStrings:SQLConnectionString"));
DbConn dbConn = new DbConn();
dbConn.sqlConnection().Execute("delete token where token_expireddate < @now", new { now = DateTime.Now });
dbConn.closeConn();
try
{
if (_httpContextAccessor.HttpContext.Request.Cookies["token_key"] == null)
{
user_isLogin = false;
error_msg = "no this cookie";
return;
}
string token_key = _httpContextAccessor.HttpContext.Request.Cookies["token_key"];
var tokenData = dbConn.sqlConnection().Query("select * from token where token_key = @token_key", new { token_key = token_key });
//CookieOptions cookieOptions = new CookieOptions();
//cookieOptions.Secure = true;
//cookieOptions.Expires = DateTime.Now.AddMinutes(intexpireMin);
if (tokenData.Count() == 0)
{
_httpContextAccessor.HttpContext.Response.Cookies.Delete("token_key");
user_isLogin = false;
error_msg = "not this account";
dbConn.closeConn();
return;
}
var tokenItem = tokenData.ElementAt(0);
if (tokenItem.user_uid == GlobalClass.appsettings("Admin:uid") && tokenItem.user_id == GlobalClass.appsettings("Admin:id"))
{
user_uid = tokenItem.user_uid;
user_id = tokenItem.user_id;
user_name = "系統管理員";
user_perm = GlobalClass.appsettings("Admin:perm");
user_isLogin = true;
int intMin = 180;
if (tokenItem.token_isremember == "Y")
{
intMin = 60 * 24 * 14;
}
dbConn.sqlConnection().Execute("update token set token_expireddate = @token_expireddate " +
"where token_key = @token_key", new { token_expireddate = DateTime.Now.AddMinutes(intMin), token_key = token_key });
dbConn.closeConn();
CookieOptions options = new CookieOptions()
{
Secure = true,
Expires = DateTime.Now.AddMinutes(intMin)
};
//_httpContextAccessor.HttpContext.Response.Cookies.Delete("web_token_key");
_httpContextAccessor.HttpContext.Response.Cookies.Append("token_key", token_key, options);
return;
}
else {
user loginUser = conn.QueryFirstOrDefault<user>("select * from users where user_uid = @user_uid and user_id = @user_id", new { user_uid = tokenItem.user_uid , user_id = tokenItem.user_id });
if (loginUser == null)
{
dbConn.sqlConnection().Execute("delete token where token_key = @token_key", new { token_key = token_key });
user_isLogin = false;
error_msg = "找不到此token用戶資料";
dbConn.closeConn();
return;
}
if (loginUser.user_onjob == "N") {
dbConn.sqlConnection().Execute("delete token where token_key = @token_key", new { token_key = token_key });
user_isLogin = false;
error_msg = "此token用戶已經離職";
dbConn.closeConn();
return;
}
user_uid = tokenItem.user_uid;
user_id = tokenItem.user_id;
user_name = loginUser.user_name;
user_perm = loginUser.user_perm;
user_isLogin = true;
int intMin = 20;
if (tokenItem.token_isremember == "Y")
{
intMin = 60 * 24 * 7;
}
dbConn.sqlConnection().Execute("update token set token_expireddate = @token_expireddate " +
"where token_key = @token_key", new { token_expireddate = DateTime.Now.AddMinutes(intMin), token_key = token_key });
CookieOptions options = new CookieOptions()
{
Secure = true,
Expires = DateTime.Now.AddMinutes(intMin)
};
//_httpContextAccessor.HttpContext.Response.Cookies.Delete("web_token_key");
_httpContextAccessor.HttpContext.Response.Cookies.Append("token_key", token_key, options);
dbConn.closeConn();
}
}
catch (Exception ex)
{
conn.Close();
dbConn.closeConn();
user_isLogin = false;
error_msg = ex.Message;
}
}
}

52
Modals/resultClass.cs Normal file
View File

@ -0,0 +1,52 @@
using System.Data.SqlClient;
using Dapper.Contrib.Extensions;
using Dapper;
using static DbTableClass;
public class resultClass
{
public class deptListResult
{
public string ret = "no";
public string err_code = "0000";
public string message = "";
public List<depts> depts = new List<depts>();
}
public class groupListResult
{
public string ret = "no";
public string err_code = "0000";
public string message = "";
public List<groupDetail> groups = new List<groupDetail>();
}
public class groupDetail : group
{
public List<user> users = new List<user>();
}
public class userWithDept : user
{
SqlConnection conn = new SqlConnection(GlobalClass.appsettings("ConnectionStrings:SQLConnectionString"));
public List<depts> Depts = new List<depts>();
public userWithDept() { }
public userWithDept(user objData) {
Type projectType = objData.GetType();
foreach (var prop in projectType.GetProperties())
{
string propName = prop.Name;
var valueProperty = projectType.GetProperty(propName);
object propValue = valueProperty.GetValue(objData, null);
this.GetType().GetProperty(propName).SetValue(this, propValue);
}
Depts = conn.Query<depts>("select * from userDept where user_uid = @user_uid", new { user_uid = this.user_uid }).ToList();
}
}
}

31
Program.cs Normal file
View File

@ -0,0 +1,31 @@
using Microsoft.Extensions.DependencyInjection.Extensions;
var builder = WebApplication.CreateBuilder(args);
// Add services to the container.
builder.Services.AddControllersWithViews();
builder.Services.TryAddSingleton<IHttpContextAccessor, HttpContextAccessor>();
var app = builder.Build();
// Configure the HTTP request pipeline.
if (!app.Environment.IsDevelopment())
{
app.UseExceptionHandler("/Error");
// The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.
app.UseHsts();
}
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseRouting();
app.UseAuthorization();
app.MapControllerRoute(
name: "default",
pattern: "{controller=Home}/{action=Login}/{id?}");
app.Run();

View File

@ -0,0 +1,38 @@
{
"$schema": "http://json.schemastore.org/launchsettings.json",
"iisSettings": {
"windowsAuthentication": false,
"anonymousAuthentication": true,
"iisExpress": {
"applicationUrl": "http://localhost:5280",
"sslPort": 44347
}
},
"profiles": {
"http": {
"commandName": "Project",
"dotnetRunMessages": true,
"launchBrowser": true,
"applicationUrl": "http://localhost:5294",
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
}
},
"https": {
"commandName": "Project",
"dotnetRunMessages": true,
"launchBrowser": true,
"applicationUrl": "https://localhost:7287;http://localhost:5294",
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
}
},
"IIS Express": {
"commandName": "IISExpress",
"launchBrowser": true,
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
}
}
}
}

53
QuotationMaker.csproj Normal file
View File

@ -0,0 +1,53 @@
<Project Sdk="Microsoft.NET.Sdk.Web">
<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<Nullable>enable</Nullable>
<ImplicitUsings>enable</ImplicitUsings>
</PropertyGroup>
<ItemGroup>
<Folder Include="wwwroot\assets\vendor\ace-builds\demo\" />
<Folder Include="wwwroot\assets\vendor\ace-builds\src\" />
<Folder Include="wwwroot\assets\vendor\cookieconsent\examples\" />
<Folder Include="wwwroot\assets\vendor\cookieconsent\src\" />
<Folder Include="wwwroot\assets\vendor\flatpickr\types\" />
<Folder Include="wwwroot\assets\vendor\flatpickr\utils\" />
<Folder Include="wwwroot\assets\vendor\flot\examples\" />
<Folder Include="wwwroot\assets\vendor\fortawesome\fontawesome-free\less\" />
<Folder Include="wwwroot\assets\vendor\fortawesome\fontawesome-free\metadata\" />
<Folder Include="wwwroot\assets\vendor\fortawesome\fontawesome-free\scss\" />
<Folder Include="wwwroot\assets\vendor\html2canvas\types\build\" />
<Folder Include="wwwroot\assets\vendor\html2canvas\types\core\__mocks__\" />
<Folder Include="wwwroot\assets\vendor\html2canvas\types\core\__tests__\" />
<Folder Include="wwwroot\assets\vendor\html2canvas\types\css\layout\__mocks__\" />
<Folder Include="wwwroot\assets\vendor\html2canvas\types\css\property-descriptors\__tests__\" />
<Folder Include="wwwroot\assets\vendor\html2canvas\types\css\syntax\__tests__\" />
<Folder Include="wwwroot\assets\vendor\html2canvas\types\css\types\functions\__tests__\" />
<Folder Include="wwwroot\assets\vendor\html2canvas\types\css\types\__tests__\" />
<Folder Include="wwwroot\assets\vendor\html2canvas\types\dom\elements\" />
<Folder Include="wwwroot\assets\vendor\html2canvas\types\dom\replaced-elements\" />
<Folder Include="wwwroot\assets\vendor\html2canvas\types\dom\__mocks__\" />
<Folder Include="wwwroot\assets\vendor\html2canvas\types\render\canvas\" />
<Folder Include="wwwroot\assets\vendor\html2canvas\types\src\" />
<Folder Include="wwwroot\assets\vendor\html2canvas\types\tests\" />
<Folder Include="wwwroot\assets\vendor\html2canvas\types\__tests__\" />
<Folder Include="wwwroot\assets\vendor\jquery-sparkline\src\" />
<Folder Include="wwwroot\assets\vendor\moment\src\" />
<Folder Include="wwwroot\assets\vendor\nouislider\distribute\" />
<Folder Include="wwwroot\assets\vendor\pace-progress\docs\" />
<Folder Include="wwwroot\assets\vendor\pace-progress\tests\" />
<Folder Include="wwwroot\assets\vendor\particles.js\demo\" />
<Folder Include="wwwroot\assets\vendor\stacked-menu\scss\" />
<Folder Include="wwwroot\assets\vendor\toastr\tests\" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="Dapper" Version="2.1.35" />
<PackageReference Include="Dapper.Contrib" Version="2.0.78" />
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
<PackageReference Include="NPOI" Version="2.7.0" />
<PackageReference Include="System.Data.SqlClient" Version="4.8.6" />
</ItemGroup>
</Project>

25
QuotationMaker.sln Normal file
View File

@ -0,0 +1,25 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 17
VisualStudioVersion = 17.9.34728.123
MinimumVisualStudioVersion = 10.0.40219.1
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "QuotationMaker", "QuotationMaker.csproj", "{CF74960F-AA62-425E-B674-8D2CADFD3D0A}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Release|Any CPU = Release|Any CPU
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{CF74960F-AA62-425E-B674-8D2CADFD3D0A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{CF74960F-AA62-425E-B674-8D2CADFD3D0A}.Debug|Any CPU.Build.0 = Debug|Any CPU
{CF74960F-AA62-425E-B674-8D2CADFD3D0A}.Release|Any CPU.ActiveCfg = Release|Any CPU
{CF74960F-AA62-425E-B674-8D2CADFD3D0A}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {728C0AFE-E2E9-4765-9662-4EB65EF7938F}
EndGlobalSection
EndGlobal

View File

@ -1,3 +1 @@
# QuotationMaker # QuotationMaker
報價單系統

26
Views/Home/Error.cshtml Normal file
View File

@ -0,0 +1,26 @@
@page
@model ErrorModel
@{
ViewData["Title"] = "Error";
}
<h1 class="text-danger">Error.</h1>
<h2 class="text-danger">An error occurred while processing your request.</h2>
@if (Model.ShowRequestId)
{
<p>
<strong>Request ID:</strong> <code>@Model.RequestId</code>
</p>
}
<h3>Development Mode</h3>
<p>
Swapping to the <strong>Development</strong> environment displays detailed information about the error that occurred.
</p>
<p>
<strong>The Development environment shouldn't be enabled for deployed applications.</strong>
It can result in displaying sensitive information from exceptions to end users.
For local debugging, enable the <strong>Development</strong> environment by setting the <strong>ASPNETCORE_ENVIRONMENT</strong> environment variable to <strong>Development</strong>
and restarting the app.
</p>

View File

@ -0,0 +1,28 @@
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.RazorPages;
using System.Diagnostics;
namespace QuotationMaker.Pages
{
[ResponseCache(Duration = 0, Location = ResponseCacheLocation.None, NoStore = true)]
[IgnoreAntiforgeryToken]
public class ErrorModel : PageModel
{
public string? RequestId { get; set; }
public bool ShowRequestId => !string.IsNullOrEmpty(RequestId);
private readonly ILogger<ErrorModel> _logger;
public ErrorModel(ILogger<ErrorModel> logger)
{
_logger = logger;
}
public void OnGet()
{
RequestId = Activity.Current?.Id ?? HttpContext.TraceIdentifier;
}
}
}

View File

@ -0,0 +1,16 @@
@*
For more information on enabling MVC for empty projects, visit https://go.microsoft.com/fwlink/?LinkID=397860
*@
@{
Layout = "_LooperLayout";
}
@section Style {
<link rel="stylesheet" href="~/assets/vendor/datatables.net-responsive-bs4/css/responsive.bootstrap4.min.css">
}
@section Script {
<script src="~/assets/vendor/sortablejs/Sortable.min.js"></script>
<script src="~/assets/vendor/nestable2/jquery.nestable.min.js"></script>
<script src="~/assets/javascript/custom/grouplist.js" asp-append-version="true"></script>
}

122
Views/Home/Login.cshtml Normal file
View File

@ -0,0 +1,122 @@
@*
For more information on enabling MVC for empty projects, visit https://go.microsoft.com/fwlink/?LinkID=397860
*@
<!DOCTYPE html>
<html lang="en">
<head>
<!-- Required meta tags -->
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no"><!-- End Required meta tags -->
<!-- Begin SEO tag -->
<title> 報價單產生器 </title>
<meta property="og:title" content="Sign In">
<meta name="author" content="詹小盤">
<meta property="og:locale" content="en_US">
<meta name="description" content="Responsive admin theme build on top of Bootstrap 4">
<meta property="og:description" content="Responsive admin theme build on top of Bootstrap 4">
<link rel="canonical" href="https://uselooper.com">
<meta property="og:url" content="https://uselooper.com">
<meta property="og:site_name" content="Looper - Bootstrap 4 Admin Theme">
<!-- End SEO tag -->
<!-- Favicons -->
<link rel="apple-touch-icon" sizes="144x144" href="~/assets/apple-touch-icon.png">
<link rel="shortcut icon" href="assets/favicon.ico">
<meta name="theme-color" content="#3063A0"><!-- Google font -->
<link href="https://fonts.googleapis.com/css?family=Fira+Sans:400,500,600" rel="stylesheet"><!-- End Google font -->
<!-- BEGIN PLUGINS STYLES -->
<link rel="stylesheet" href="~/assets/vendor/fortawesome/fontawesome-free/css/all.min.css"><!-- END PLUGINS STYLES -->
<!-- BEGIN THEME STYLES -->
<link rel="stylesheet" href="~/assets/stylesheets/theme.min.css" data-skin="default">
<link rel="stylesheet" href="~/assets/stylesheets/theme-dark.min.css" data-skin="dark">
<link rel="stylesheet" href="~/assets/stylesheets/custom.css">
<script>
var skin = localStorage.getItem('skin') || 'default';
var isCompact = JSON.parse(localStorage.getItem('hasCompactMenu'));
var disabledSkinStylesheet = document.querySelector('link[data-skin]:not([data-skin="' + skin + '"])');
// Disable unused skin immediately
disabledSkinStylesheet.setAttribute('rel', '');
disabledSkinStylesheet.setAttribute('disabled', true);
// add flag class to html immediately
if (isCompact == true) document.querySelector('html').classList.add('preparing-compact-menu');
</script><!-- END THEME STYLES -->
</head>
<body>
<!--[if lt IE 10]>
<div class="page-message" role="alert">You are using an <strong>outdated</strong> browser. Please <a class="alert-link" href="http://browsehappy.com/">upgrade your browser</a> to improve your experience and security.</div>
<![endif]-->
<!-- .auth -->
<main class="auth">
<header id="auth-header" class="auth-header" style="background-image: url(/assets/images/illustration/img-1.png);">
<h1>
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" height="64" viewbox="0 0 351 100">
<defs>
<path id="a" d="M156.538 45.644v1.04a6.347 6.347 0 0 1-1.847 3.98L127.708 77.67a6.338 6.338 0 0 1-3.862 1.839h-1.272a6.34 6.34 0 0 1-3.862-1.839L91.728 50.664a6.353 6.353 0 0 1 0-9l9.11-9.117-2.136-2.138a3.171 3.171 0 0 0-4.498 0L80.711 43.913a3.177 3.177 0 0 0-.043 4.453l-.002.003.048.047 24.733 24.754-4.497 4.5a6.339 6.339 0 0 1-3.863 1.84h-1.27a6.337 6.337 0 0 1-3.863-1.84L64.971 50.665a6.353 6.353 0 0 1 0-9l26.983-27.008a6.336 6.336 0 0 1 4.498-1.869c1.626 0 3.252.622 4.498 1.87l26.986 27.006a6.353 6.353 0 0 1 0 9l-9.11 9.117 2.136 2.138a3.171 3.171 0 0 0 4.498 0l13.49-13.504a3.177 3.177 0 0 0 .046-4.453l.002-.002-.047-.048-24.737-24.754 4.498-4.5a6.344 6.344 0 0 1 8.996 0l26.983 27.006a6.347 6.347 0 0 1 1.847 3.98zm-46.707-4.095l-2.362 2.364a3.178 3.178 0 0 0 0 4.501l2.362 2.364 2.361-2.364a3.178 3.178 0 0 0 0-4.501l-2.361-2.364z"></path>
</defs>
<g fill="none" fill-rule="evenodd">
<path fill="currentColor" fill-rule="nonzero" d="M39.252 80.385c-13.817 0-21.06-8.915-21.06-22.955V13.862H.81V.936h33.762V58.1c0 6.797 4.346 9.026 9.026 9.026 2.563 0 5.237-.446 8.58-1.783l3.677 12.034c-5.794 1.894-9.694 3.009-16.603 3.009zM164.213 99.55V23.78h13.372l1.225 5.571h.335c4.457-4.011 10.585-6.908 16.491-6.908 13.817 0 22.174 11.031 22.174 28.08 0 18.943-11.588 29.863-23.957 29.863-4.903 0-9.694-2.117-13.594-6.017h-.446l.78 9.025V99.55h-16.38zm25.852-32.537c6.128 0 10.92-4.903 10.92-16.268 0-9.917-3.232-14.932-10.14-14.932-3.566 0-6.797 1.56-10.252 5.126v22.397c3.12 2.674 6.686 3.677 9.472 3.677zm69.643 13.372c-17.272 0-30.643-10.586-30.643-28.972 0-18.163 13.928-28.971 28.748-28.971 17.049 0 26.075 11.477 26.075 26.52 0 3.008-.558 6.017-.78 7.354h-37.663c1.56 8.023 7.465 11.589 16.491 11.589 5.014 0 9.36-1.337 14.263-3.9l5.46 9.917c-6.351 4.011-14.597 6.463-21.951 6.463zm-1.338-45.463c-6.462 0-11.031 3.454-12.702 10.363h23.622c-.78-6.797-4.568-10.363-10.92-10.363zm44.238 44.126V23.779h13.371l1.337 12.034h.334c5.46-9.025 13.595-13.371 22.398-13.371 4.902 0 7.465.78 10.697 2.228l-3.343 13.706c-3.454-1.003-5.683-1.56-9.806-1.56-6.797 0-13.928 3.566-18.608 13.483v28.749h-16.38z"></path>
<use class="fill-warning" xlink:href="#a"></use>
</g>
</svg> <span class="sr-only">Sign In</span>
</h1>
<p>
</p>
</header><!-- form -->
<form class="auth-form">
<!-- .form-group -->
<div class="form-group">
<div class="form-label-group">
<input type="text" id="inputUser" class="form-control" placeholder="帳號" autofocus=""> <label for="inputUser">帳號</label>
</div>
</div><!-- /.form-group -->
<!-- .form-group -->
<div class="form-group">
<div class="form-label-group">
<input type="password" id="inputPassword" class="form-control" placeholder="密碼"> <label for="inputPassword">密碼</label>
</div>
</div><!-- /.form-group -->
<!-- .form-group -->
<div class="form-group">
<button class="btn btn-lg btn-primary btn-block" type="button" id="loginBtn">登入</button>
</div><!-- /.form-group -->
<!-- .form-group -->
<div class="form-group text-center">
<div class="custom-control custom-control-inline custom-checkbox">
<input type="checkbox" class="custom-control-input" id="remember-me"> <label class="custom-control-label" for="remember-me">Keep me sign in</label>
</div>
</div><!-- /.form-group -->
<!-- recovery links -->
<div class="text-center pt-3" style="visibility:hidden;">
<a href="auth-recovery-username.html" class="link">Forgot Username?</a> <span class="mx-2">·</span> <a href="auth-recovery-password.html" class="link">Forgot Password?</a>
</div><!-- /recovery links -->
</form><!-- /.auth-form -->
<!-- copyright -->
<footer class="auth-footer">
© 2024 All Rights Reserved. <a href="#">Privacy</a> and <a href="#">Terms</a>
</footer>
</main><!-- /.auth -->
<!-- BEGIN BASE JS -->
<script src="~/assets/vendor/jquery/jquery.min.js"></script>
<script src="~/assets/vendor/jquery.cookie/jquery.cookie.js"></script>
<script src="~/assets/vendor/sha256/sha256.js"></script>
<script src="~/assets/vendor/popper.js/umd/popper.min.js"></script>
<script src="~/assets/vendor/bootstrap/js/bootstrap.min.js"></script>
<script src="~/assets/javascript/custom/globaljs.js"></script>
<script src="~/assets/javascript/custom/login.js?v=1"></script>
<!-- END BASE JS -->
<!-- BEGIN PLUGINS JS -->
<script src="~/assets/vendor/particles.js/particles.js"></script>
<script>
/**
* Keep in mind that your scripts may not always be executed after the theme is completely ready,
* you might need to observe the `theme:load` event to make sure your scripts are executed after the theme is ready.
*/
$(document).on('theme:init', () => {
particlesJS.load('auth-header', '/assets/javascript/pages/particles.json');
})
</script> <!-- END PLUGINS JS -->
<!-- BEGIN THEME JS -->
<script src="~/assets/javascript/theme.js"></script> <!-- END THEME JS -->
</body>
</html>

View File

@ -0,0 +1,8 @@
@page
@model PrivacyModel
@{
ViewData["Title"] = "Privacy Policy";
}
<h1>@ViewData["Title"]</h1>
<p>Use this page to detail your site's privacy policy.</p>

View File

@ -0,0 +1,20 @@
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.RazorPages;
namespace QuotationMaker.Pages
{
public class PrivacyModel : PageModel
{
private readonly ILogger<PrivacyModel> _logger;
public PrivacyModel(ILogger<PrivacyModel> logger)
{
_logger = logger;
}
public void OnGet()
{
}
}
}

View File

@ -0,0 +1,468 @@
@*
For more information on enabling MVC for empty projects, visit https://go.microsoft.com/fwlink/?LinkID=397860
*@
@{
Layout = "_LooperLayout";
}
@section Style {
<style type="text/css">
.cards tbody tr {
float: left;
width: 19rem;
margin: 0.5rem;
border: 0.0625rem solid rgba(0, 0, 0, .125);
border-radius: .25rem;
box-shadow: 0.25rem 0.25rem 0.5rem rgba(0, 0, 0, 0.25);
}
.cards tbody td {
display: block;
}
.cards thead {
display: none;
}
.cards td:before {
content: attr(data-label);
position: relative;
float: left;
color: #808080;
min-width: 4rem;
margin-left: 0;
margin-right: 1rem;
text-align: left;
}
tr.selected td:before {
color: #CCC;
}
.table .avatar {
width: 50px;
}
.cards .avatar {
width: 150px;
height: 150px;
margin: 15px;
}
</style>
}
@section Script {
<script src="~/assets/vendor/datatables.net/js/jquery.dataTables.min.js"></script>
<script src="~/assets/vendor/datatables.net-responsive/js/dataTables.responsive.min.js"></script>
<script src="~/assets/vendor/datatables.net-responsive-bs4/js/responsive.bootstrap4.min.js"></script>
<script src="~/assets/javascript/pages/dataTables.bootstrap.js"></script>
<script src="~/assets/javascript/custom/projectlist.js" asp-append-version="true"></script>
}
<!-- .page-inner -->
<div class="page-inner">
<!-- .page-title-bar -->
<header class="page-title-bar">
<!-- .breadcrumb -->
<nav aria-label="breadcrumb">
<ol class="breadcrumb">
<li class="breadcrumb-item active">
<a href="#"><i class="breadcrumb-icon fa fa-angle-left mr-2"></i>報價單清單</a>
</li>
</ol>
</nav><!-- /.breadcrumb -->
<!-- title -->
<h1 class="page-title"> 報價單清單 </h1>
<p class="text-muted"> </p><!-- /title -->
</header><!-- /.page-title-bar -->
<div class="page-section">
<div class="row">
<div class="col-lg-12">
<!-- #accordion2 -->
<div id="accordion1" class="card-expansion">
<!-- .card -->
<div class="card card-expansion-item expanded">
<div class="card-header border-0" id="headingOne1">
<button id="adv-search-btn" class="btn btn-reset d-flex justify-content-between w-100" data-toggle="collapse" data-target="#collapseOne1" aria-expanded="false" aria-controls="collapseOne1"><span>進階搜尋</span> <span class="collapse-indicator"><i class="fa fa-fw fa-chevron-down"></i></span></button>
</div>
<div>
<div id="collapseOne1" class="collapse" aria-labelledby="headingOne1" data-parent="#accordion1">
<div class="card-body pt-0">
<div class="row">
<div class="col-md-4">
<div class="form-group">
<label class="control-label" for="dateStart">起</label>
<input id="dateStart" type="text" class="form-control flatpickr-input active" data-toggle="flatpickr" data-date-format="m.y" data-monthselect="true" readonly="readonly">
</div>
</div>
<div class="col-md-4">
<div class="form-group">
<label class="control-label" for="dateEnd">迄</label>
<input id="dateEnd" type="text" class="form-control flatpickr-input active" data-toggle="flatpickr" data-date-format="m.y" data-monthselect="true" readonly="readonly">
</div>
</div>
<div class="col-md-4">
<div class="form-group">
<label class="d-block">狀況</label>
<div class="custom-control custom-control-inline custom-radio">
<input type="radio" class="custom-control-input" name="rdGroup1[]" id="rd11" value="Y"> <label class="custom-control-label" for="rd11">執行</label>
</div>
<div class="custom-control custom-control-inline custom-radio">
<input type="radio" class="custom-control-input" name="rdGroup1[]" id="rd21" value="N"> <label class="custom-control-label" for="rd21">未執行</label>
</div>
<div class="custom-control custom-control-inline custom-radio">
<input type="radio" class="custom-control-input" name="rdGroup1[]" id="rd31" value="A" checked=""> <label class="custom-control-label" for="rd31">全部</label>
</div>
</div>
</div>
</div>
<div class="col-md-12">
<button type="button" id="filiterBtn" class="btn btn-primary">篩選</button>
<button type="button" id="resetBtn" class="btn btn-danger">重設</button>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<!-- .page-section -->
<div class="page-section">
<button type="button" id="projectNewModal" class="btn btn-primary btn-floated" title="Add new client"><i class="fa fa-plus"></i></button>
<!-- .card -->
<div class="card card-fluid">
<!-- .card-body -->
<div class="card-body">
<!-- .table -->
<table id="dt-responsive" class="table dt-responsive nowrap w-100">
<thead>
<tr>
<th> 年度 </th>
<th> 案號 </th>
<th> 專案名稱 </th>
<th> 狀態 </th>
<th> 合作對象 </th>
<th> 資料異動時間 </th>
<th> </th>
</tr>
</thead>
</table><!-- /.table -->
</div><!-- /.card-body -->
</div><!-- /.card -->
</div><!-- /.page-section -->
</div><!-- /.page-inner -->
<!-- Keep in mind that modals should be placed outsite of page sidebar -->
<!-- .modal -->
<form id="clientNewForm" name="clientNewForm">
<div class="modal fade" id="clientNewModal" tabindex="-1" role="dialog" aria-labelledby="clientNewModalLabel" data-backdrop="static"
data-keyboard="false" aria-hidden="true">
<!-- .modal-dialog -->
<div class="modal-dialog modal-lg" role="document">
<!-- .modal-content -->
<div class="modal-content">
<!-- .modal-header -->
<div class="modal-header">
<h6 id="clientNewModalLabel" class="modal-title inline-editable">
<span class="sr-only">Client name</span> <input id="modelTitle" type="text" class="form-control form-control-lg" placeholder="專案資料維護" required="">
</h6>
<button type="button" class="close" data-dismiss="modal">
<span aria-hidden="true">&times;</span><span class="sr-only">Close</span>
</button>
</div><!-- /.modal-header -->
<!-- .modal-body -->
<div class="modal-body">
<input type="hidden" id="method" />
<input type="hidden" id="project_uid" />
<!-- .form-row -->
<div class="form-row">
<div class="col-md-12" id="user_name_div">
<div class="form-group">
<label class="d-block">狀態</label>
<div class="custom-control custom-control-inline custom-radio">
<input type="radio" class="custom-control-input" name="project_isExec[]" id="rd1" value="yes"> <label class="custom-control-label" for="rd1"> 已執行</label>
</div>
<div class="custom-control custom-control-inline custom-radio">
<input type="radio" class="custom-control-input" name="project_isExec[]" id="rd2" value="no"> <label class="custom-control-label" for="rd2"> 僅提案</label>
</div>
</div>
</div>
<div class="col-md-12" id="prm_project_serial">
<!-- .form-group -->
<div class="form-group">
<label class="control-label" for="select2-data-remote">PRM專案名稱</label> <select id="select2-data-remote" class="form-control">
</select>
</div><!-- /.form-group -->
<div class="form-group" id="file_div">
<label for="project_file">報價單下載 </label>
<a href="#" class="btn btn-danger" target="_blank" id="fileUrl">Go somewhere</a>
</div>
</div>
<div class="col-md-12" id="project_year_month_div">
<div class="row">
<div class="col-md-6">
<div class="form-group">
<label for="project_year">年度</label>
<select class="custom-select" id="project_year" required="">
</select>
</div>
</div>
<div class="col-md-6">
<div class="form-group">
<label for="project_month">月份</label>
<select class="custom-select" id="project_month" required="">
</select>
</div>
</div>
</div>
</div>
<div class="col-md-12" id="project_name_div">
<div class="form-group">
<label for="project_name">專案名稱</label> <input type="text" id="project_name" class="form-control">
</div>
</div>
</div><!-- /.form-row -->
</div><!-- /.modal-body -->
<!-- .modal-footer -->
<div class="modal-footer">
<button type="button" id="projectSaveBtn" class="btn btn-primary">儲存</button> <button id="closeBtn" type="button" class="btn btn-light" data-dismiss="modal">關閉</button>
</div><!-- /.modal-footer -->
</div><!-- /.modal-content -->
</div><!-- /.modal-dialog -->
</div>
</form><!-- /.modal -->
<!-- .modal -->
<form id="clientPreivewForm" name="clientPreviewForm">
<div class="modal fade" id="clientPreviewModal" tabindex="-1" role="dialog" aria-labelledby="clientPreviewModalLabel" data-backdrop="static" aria-hidden="true">
<!-- .modal-dialog -->
<div class="modal-dialog modal-lg" role="document">
<!-- .modal-content -->
<div class="modal-content">
<!-- .modal-header -->
<div class="modal-header">
<h6 id="socialModalLabel" class="modal-title inline-editable">
<span class="sr-only">合作列表</span> <input id="previewKol_name1" type="text" class="form-control form-control-lg" value="" placeholder="" readonly="readonly" required="">
</h6>
<button type="button" class="close" data-dismiss="modal">
<span aria-hidden="true">&times;</span><span class="sr-only">Close</span>
</button>
</div><!-- /.modal-header -->
<!-- .modal-body -->
<div class="modal-body">
<div class="col-md-12">
<!-- .card-body -->
<div class="card-body">
<h4 class="card-title"> 合作對象與評價 </h4><!-- .table-responsive -->
<div class="table-responsive">
<table class="table table-hover" style="min-width: 578px" id="preview_kol_table">
<thead>
<tr>
<th> 合作對象 </th>
<th> 執行 </th>
<th> 評價 </th>
</tr>
</thead>
<tbody>
<tr>
<td class="align-middle"> 754000 </td>
<td class="align-middle"> 754000 </td>
<td class="align-middle"> 754000 </td>
</tr>
</tbody>
</table>
</div><!-- /.table-responsive -->
</div><!-- /.card-body -->
</div>
</div><!-- /.modal-body -->
<!-- .modal-footer -->
<div class="modal-footer">
<button type="button" class="btn btn-light" data-toggle="modal" data-target="#clientPreviewModal">Close</button>
</div><!-- /.modal-footer -->
</div><!-- /.modal-content -->
</div><!-- /.modal-dialog -->
</div>
</form><!-- /.modal -->
<!-- .modal -->
<form id="clientCasePreivewForm" name="clientCasePreviewForm">
<div class="modal fade" id="clientCasePreviewModal" tabindex="-1" role="dialog" aria-labelledby="clientCasePreviewModalLabel" data-backdrop="static" aria-hidden="true">
<!-- .modal-dialog -->
<div class="modal-dialog modal-lg" role="document">
<!-- .modal-content -->
<div class="modal-content">
<!-- .modal-header -->
<div class="modal-header">
<h6 id="socialModalLabel" class="modal-title inline-editable">
<span class="sr-only">合作狀況</span> <input id="previewKol_name1" type="text" class="form-control form-control-lg" value="" placeholder="合作項目" readonly="readonly " required="">
</h6>
<button type="button" class="close" data-dismiss="modal">
<span aria-hidden="true">&times;</span><span class="sr-only">Close</span>
</button>
</div><!-- /.modal-header -->
<!-- .modal-body -->
<div class="modal-body">
<div class="form-row">
<!-- form column -->
<label for="input02" class="col-md-3">案件名稱</label> <!-- /form column -->
<!-- form column -->
<div class="col-md-9 mb-3">
<input type="text" class="form-control" id="previewProject_name" value="" readonly="readonly">
</div><!-- /form column -->
</div>
<div class="form-row">
<!-- form column -->
<label for="input03" class="col-md-3">合作形式</label> <!-- /form column -->
<!-- form column -->
<div class="col-md-9 mb-3">
<input type="text" class="form-control" id="previewProject_Cooper" readonly="readonly"></input>
</div><!-- /form column -->
</div>
<div class="col-md-12">
<h2 class="card-title"> 報價 </h2><!-- .table-responsive -->
<div class="table-responsive">
<table class="table table-hover" style="min-width: 678px" id="previewPrice_table">
<thead>
<tr>
<th style="width: 10%;"> 合作平台 </th>
<th style="width: 30%;"> 規格 </th>
<th style="width: 10%; text-align: right;"> 數量 </th>
<th style="width: 10%; text-align: right;"> 報價 </th>
<th> 報價日期</th>
</tr>
</thead>
<tbody>
<tr>
<td class="align-middle"> Instagram </td>
<td class="align-middle"> https://www.instagram.com/zamy_ding/ </td>
<td class="align-middle"> zamy_ding </td>
<td class="align-middle"> 奎丁 </td>
<td class="align-middle"> 754000 </td>
</tr>
</tbody>
</table>
</div><!-- /.table-responsive -->
</div>
<div class="col-md-12">
<!-- .form-group -->
<div class="form-group">
<h2 class="card-title">確認合作</h2>
<div class="col-md-9 mb-3">
<input type="text" class="form-control" id="previewProject_isCooper" readonly="readonly"></input>
</div><!-- /form column -->
</div><!-- /.form-group -->
<div class="card-footer">&nbsp;</div>
</div>
<div class="col-md-12" id="fileDiv" style="display: none;">
<h2 class="card-title"> 合約 </h2><!-- .table-responsive -->
<div class="table-responsive">
<table class="table table-hover" style="min-width: 678px" id="previewFile_table">
<thead>
<tr>
<th> 檔名 </th>
</tr>
</thead>
<tbody>
<tr>
<td class="align-middle"> https://www.instagram.com/zamy_ding/ </td>
</tr>
</tbody>
</table>
</div><!-- /.table-responsive -->
</div>
<div class="col-md-12" id="isCooperate_div">
<div class="form-group">
<h2 class="card-title">評價</h2>
<!-- form column -->
<div class="col-md-9 mb-3">
<input type="text" class="form-control" id="previewProject_Quality" readonly="readonly"></input>
</div><!-- /form column -->
</div><!-- /.form-group -->
<div class="card-footer">&nbsp;</div>
</div>
<div class="col-md-12" id="isCooperate2_div">
<h2 class="card-title"> 上刊連結 </h2><!-- .table-responsive -->
<div class="table-responsive">
<table class="table table-hover" style="min-width: 678px" id="previewLink_table">
<thead>
<tr>
<th> 連結 </th>
</tr>
</thead>
<tbody>
<tr>
<td class="align-middle"> https://www.instagram.com/zamy_ding/ </td>
</tr>
</tbody>
</table>
</div><!-- /.table-responsive -->
</div>
<div class="col-md-12" id="isCooperate3_div">
<h2 class="card-title"> 截圖 </h2><!-- .table-responsive -->
<div class="table-responsive">
<table class="table table-hover" style="min-width: 678px" id="previewCut_table">
<thead>
<tr>
<th style="width: 30%;"> 截圖 </th>
<th> 說明文字</th>
</tr>
</thead>
<tbody>
<tr>
<td class="align-middle"> https://www.instagram.com/zamy_ding/ </td>
<td class="align-middle ">
</td>
</tr>
</tbody>
</table>
</div><!-- /.table-responsive -->
</div>
<div class="col-md-12" >
<!-- .form-group -->
<div class="form-group">
<h2 for="lbl3" class="card-title">附註 <span class="badge badge-secondary"><em>選填</em></span></h2>
<textarea class="form-control" id="previewkolProject_memo" rows="4" placeholder=""></textarea>
</div><!-- /.form-group -->
</div>
</div><!-- /.modal-body -->
<!-- .modal-footer -->
<div class="modal-footer">
<button type="button" class="btn btn-light" data-toggle="modal" data-target="#clientCasePreviewModal">Close</button>
</div><!-- /.modal-footer -->
</div><!-- /.modal-content -->
</div><!-- /.modal-dialog -->
</div>
</form><!-- /.modal -->

156
Views/Home/UserList.cshtml Normal file
View File

@ -0,0 +1,156 @@
@*
For more information on enabling MVC for empty projects, visit https://go.microsoft.com/fwlink/?LinkID=397860
*@
@{
Layout = "_LooperLayout";
}
@section Style {
<link rel="stylesheet" href="~/assets/vendor/datatables.net-responsive-bs4/css/responsive.bootstrap4.min.css">
}
@section Script {
<script src="~/assets/vendor/datatables.net/js/jquery.dataTables.min.js"></script>
<script src="~/assets/vendor/datatables.net-responsive/js/dataTables.responsive.min.js"></script>
<script src="~/assets/vendor/datatables.net-responsive-bs4/js/responsive.bootstrap4.min.js"></script>
<script src="~/assets/javascript/pages/dataTables.bootstrap.js"></script>
<script src="~/assets/javascript/custom/userlist.js" asp-append-version="true"></script>
}
<!-- .page-inner -->
<div class="page-inner">
<!-- .page-title-bar -->
<header class="page-title-bar">
<!-- .breadcrumb -->
<nav aria-label="breadcrumb">
<ol class="breadcrumb">
<li class="breadcrumb-item active">
<a href="#"><i class="breadcrumb-icon fa fa-angle-left mr-2"></i>使用者清單</a>
</li>
</ol>
</nav><!-- /.breadcrumb -->
<!-- title -->
<h1 class="page-title"> 系統使用者清單 </h1>
<p class="text-muted"> </p><!-- /title -->
</header><!-- /.page-title-bar -->
<!-- .page-section -->
<div class="page-section">
<button type="button" id="userNewModal" class="btn btn-primary btn-floated position-absolute" title="Add new client"><i class="fa fa-plus"></i></button>
<!-- .card -->
<div class="card card-fluid">
<!-- .card-body -->
<div class="card-body">
<!-- .table -->
<table id="dt-responsive" class="table dt-responsive nowrap w-100">
<thead>
<tr>
<th> 姓名 </th>
<th> 帳號 </th>
<th> 類型 </th>
<th> 權限 </th>
<th> 上次登入 </th>
<th> 功能 </th>
</tr>
</thead>
<tfoot>
<tr>
<th> 姓名 </th>
<th> 帳號 </th>
<th> 類型 </th>
<th> 權限 </th>
<th> 上次登入 </th>
<th> 功能 </th>
</tr>
</tfoot>
</table><!-- /.table -->
</div><!-- /.card-body -->
</div><!-- /.card -->
</div><!-- /.page-section -->
</div><!-- /.page-inner -->
<!-- Keep in mind that modals should be placed outsite of page sidebar -->
<!-- .modal -->
<form id="clientNewForm" name="clientNewForm">
<div class="modal fade" id="clientNewModal" tabindex="-1" role="dialog" aria-labelledby="clientNewModalLabel" aria-hidden="true">
<!-- .modal-dialog -->
<div class="modal-dialog" role="document">
<!-- .modal-content -->
<div class="modal-content">
<!-- .modal-header -->
<div class="modal-header">
<h6 id="clientNewModalLabel" class="modal-title inline-editable">
<span class="sr-only">Client name</span> <input id="modelTitle" type="text" class="form-control form-control-lg" placeholder="使用者資料維護" required="">
</h6>
</div><!-- /.modal-header -->
<!-- .modal-body -->
<div class="modal-body">
<input type="hidden" id="method"/>
<input type="hidden" id="user_uid"/>
<!-- .form-row -->
<div class="form-row">
<div class="col-md-12">
<div class="form-group">
<label for="cnCountry">帳號類型</label> <select id="user_type" class="custom-select d-block w-100">
<option value="N"> E白板帳號 </option>
<option value="Y"> 自建帳號 </option>
</select>
</div>
</div>
<div class="col-md-12" id="user_elab_div">
<div class="form-group">
<label for="cnCountry">帳號名稱</label> <select id="user_elabName" class="custom-select d-block w-100">
<option value=""> Choose... </option>
</select>
</div>
</div>
<div class="col-md-12" id="user_name_div">
<div class="form-group">
<label for="user_name">使用者名稱</label> <input type="text" id="user_name" class="form-control">
</div>
</div>
<div class="col-md-12" id="user_id_div">
<div class="form-group">
<label for="user_id">使用者帳號</label> <input type="text" id="user_id" class="form-control">
</div>
</div>
<div class="col-md-6" id="user_pwd_div">
<div class="form-group">
<label for="user_pwd">使用者密碼</label> <input type="password" id="user_pwd" class="form-control">
</div>
</div>
<div class="col-md-6" id="user_chkpwd_div">
<div class="form-group">
<label for="user_chkpwd">密碼再確認</label> <input type="password" id="user_chkpwd" class="form-control">
</div>
</div>
<div class="col-md-12" id="user_email_div">
<div class="form-group">
<label for="user_email">使用者Email</label> <input type="email" id="user_email" class="form-control">
</div>
</div>
<div class="col-md-12" id="user_perm_div">
<div class="form-group">
<label for="user_perm">帳號權限</label> <select id="user_perm" class="custom-select d-block w-100">
<option value=""> Choose... </option>
<option value="user"> 一般用戶 </option>
<option value="system"> 管理用戶 </option>
</select>
</div>
</div>
<div class="col-md-12" id="user_dept_div">
<div class="form-group">
</div>
</div>
</div><!-- /.form-row -->
</div><!-- /.modal-body -->
<!-- .modal-footer -->
<div class="modal-footer">
<button type="button" id="saveBtn" class="btn btn-primary">儲存</button> <button id="closeBtn" type="button" class="btn btn-light" data-dismiss="modal">關閉</button>
</div><!-- /.modal-footer -->
</div><!-- /.modal-content -->
</div><!-- /.modal-dialog -->
</div>
</form><!-- /.modal -->

View File

@ -0,0 +1,234 @@
<!DOCTYPE html>
<html>
<head>
<!-- Required meta tags -->
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no"><!-- End Required meta tags -->
<!-- Begin SEO tag -->
<title> 報價單產生器 </title>
<meta property="og:title" content="報價單產生器">
<meta name="author" content="詹小弟">
<meta property="og:locale" content="zh_TW">
<meta name="description" content="Responsive admin theme build on top of Bootstrap 4">
<meta property="og:description" content="Responsive admin theme build on top of Bootstrap 4">
<link rel="canonical" href="https://uselooper.com">
<meta property="og:url" content="https://uselooper.com">
<meta property="og:site_name" content="Looper - Bootstrap 4 Admin Theme">
<!-- End SEO tag -->
<!-- FAVICONS -->
<link rel="apple-touch-icon" sizes="144x144" href="~/assets/apple-touch-icon.png">
<link rel="shortcut icon" href="~/assets/favicon.ico">
<meta name="theme-color" content="#3063A0"><!-- End FAVICONS -->
<!-- GOOGLE FONT -->
<link href="https://fonts.googleapis.com/css?family=Fira+Sans:400,500,600" rel="stylesheet"><!-- End GOOGLE FONT -->
<!-- BEGIN PLUGINS STYLES -->
<link rel="stylesheet" href="~/assets/vendor/open-iconic/font/css/open-iconic-bootstrap.min.css">
<link rel="stylesheet" href="~/assets/vendor/fortawesome/fontawesome-free/css/all.min.css">
<link rel="stylesheet" href="~/assets/vendor/select2/css/select2.min.css">
<link rel="stylesheet" href="~/assets/vendor/tributejs/tribute.css">
<link rel="stylesheet" href="~/assets/vendor/at.js/css/jquery.atwho.min.css">
<link rel="stylesheet" href="~/assets/vendor/bootstrap-select/css/bootstrap-select.min.css">
<link rel="stylesheet" href="~/assets/vendor/flatpickr/flatpickr.min.css">
<link rel="stylesheet" href="~/assets/vendor/bootstrap-colorpicker/css/bootstrap-colorpicker.min.css">
<link rel="stylesheet" href="~/assets/vendor/bootstrap-touchspin/jquery.bootstrap-touchspin.min.css">
<link rel="stylesheet" href="~/assets/vendor/nouisliderribute/nouislider.min.css">
<!-- END PLUGINS STYLES -->
<!-- BEGIN THEME STYLES -->
<link rel="stylesheet" href="~/assets/stylesheets/theme.css" data-skin="default">
<link rel="stylesheet" href="~/assets/stylesheets/theme-dark.css" data-skin="dark">
@RenderSection("Style", required: false)
<link rel="stylesheet" href="~/assets/stylesheets/custom.css">
<script>
var skin = localStorage.getItem('skin') || 'default';
var isCompact = JSON.parse(localStorage.getItem('hasCompactMenu'));
var disabledSkinStylesheet = document.querySelector('link[data-skin]:not([data-skin="' + skin + '"])');
// Disable unused skin immediately
disabledSkinStylesheet.setAttribute('rel', '');
disabledSkinStylesheet.setAttribute('disabled', true);
// add flag class to html immediately
if (isCompact == true) document.querySelector('html').classList.add('preparing-compact-menu');
</script><!-- END THEME STYLES -->
</head>
<body>
<!-- .app -->
<div class="app">
<!--[if lt IE 10]>
<div class="page-message" role="alert">You are using an <strong>outdated</strong> browser. Please <a class="alert-link" href="http://browsehappy.com/">upgrade your browser</a> to improve your experience and security.</div>
<![endif]-->
<!-- .app-header -->
<header class="app-header app-header-dark">
<!-- .top-bar -->
<div class="top-bar">
<!-- .top-bar-brand -->
<div class="top-bar-brand">
<!-- toggle aside menu -->
<button class="hamburger hamburger-squeeze mr-2" type="button" data-toggle="aside-menu" aria-label="toggle aside menu"><span class="hamburger-box"><span class="hamburger-inner"></span></span></button> <!-- /toggle aside menu -->
<a href="index.html">
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" height="28" viewbox="0 0 351 100">
<defs>
<path id="a" d="M156.538 45.644v1.04a6.347 6.347 0 0 1-1.847 3.98L127.708 77.67a6.338 6.338 0 0 1-3.862 1.839h-1.272a6.34 6.34 0 0 1-3.862-1.839L91.728 50.664a6.353 6.353 0 0 1 0-9l9.11-9.117-2.136-2.138a3.171 3.171 0 0 0-4.498 0L80.711 43.913a3.177 3.177 0 0 0-.043 4.453l-.002.003.048.047 24.733 24.754-4.497 4.5a6.339 6.339 0 0 1-3.863 1.84h-1.27a6.337 6.337 0 0 1-3.863-1.84L64.971 50.665a6.353 6.353 0 0 1 0-9l26.983-27.008a6.336 6.336 0 0 1 4.498-1.869c1.626 0 3.252.622 4.498 1.87l26.986 27.006a6.353 6.353 0 0 1 0 9l-9.11 9.117 2.136 2.138a3.171 3.171 0 0 0 4.498 0l13.49-13.504a3.177 3.177 0 0 0 .046-4.453l.002-.002-.047-.048-24.737-24.754 4.498-4.5a6.344 6.344 0 0 1 8.996 0l26.983 27.006a6.347 6.347 0 0 1 1.847 3.98zm-46.707-4.095l-2.362 2.364a3.178 3.178 0 0 0 0 4.501l2.362 2.364 2.361-2.364a3.178 3.178 0 0 0 0-4.501l-2.361-2.364z"></path>
</defs>
<g fill="none" fill-rule="evenodd">
<path fill="currentColor" fill-rule="nonzero" d="M39.252 80.385c-13.817 0-21.06-8.915-21.06-22.955V13.862H.81V.936h33.762V58.1c0 6.797 4.346 9.026 9.026 9.026 2.563 0 5.237-.446 8.58-1.783l3.677 12.034c-5.794 1.894-9.694 3.009-16.603 3.009zM164.213 99.55V23.78h13.372l1.225 5.571h.335c4.457-4.011 10.585-6.908 16.491-6.908 13.817 0 22.174 11.031 22.174 28.08 0 18.943-11.588 29.863-23.957 29.863-4.903 0-9.694-2.117-13.594-6.017h-.446l.78 9.025V99.55h-16.38zm25.852-32.537c6.128 0 10.92-4.903 10.92-16.268 0-9.917-3.232-14.932-10.14-14.932-3.566 0-6.797 1.56-10.252 5.126v22.397c3.12 2.674 6.686 3.677 9.472 3.677zm69.643 13.372c-17.272 0-30.643-10.586-30.643-28.972 0-18.163 13.928-28.971 28.748-28.971 17.049 0 26.075 11.477 26.075 26.52 0 3.008-.558 6.017-.78 7.354h-37.663c1.56 8.023 7.465 11.589 16.491 11.589 5.014 0 9.36-1.337 14.263-3.9l5.46 9.917c-6.351 4.011-14.597 6.463-21.951 6.463zm-1.338-45.463c-6.462 0-11.031 3.454-12.702 10.363h23.622c-.78-6.797-4.568-10.363-10.92-10.363zm44.238 44.126V23.779h13.371l1.337 12.034h.334c5.46-9.025 13.595-13.371 22.398-13.371 4.902 0 7.465.78 10.697 2.228l-3.343 13.706c-3.454-1.003-5.683-1.56-9.806-1.56-6.797 0-13.928 3.566-18.608 13.483v28.749h-16.38z"></path>
<use class="fill-warning" xlink:href="#a"></use>
</g>
</svg>
</a>
</div><!-- /.top-bar-brand -->
<!-- .top-bar-list -->
<div class="top-bar-list">
<!-- .top-bar-item -->
<div class="top-bar-item px-2 d-md-none d-lg-none d-xl-none">
<!-- toggle menu -->
<button class="hamburger hamburger-squeeze" type="button" data-toggle="aside" aria-label="toggle menu"><span class="hamburger-box"><span class="hamburger-inner"></span></span></button> <!-- /toggle menu -->
</div><!-- /.top-bar-item -->
<!-- .top-bar-item -->
<div class="top-bar-item top-bar-item-right px-0">
<!-- .btn-account -->
<div class="dropdown d-none d-sm-flex">
<button class="btn-account" type="button" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false"><span class="user-avatar user-avatar-md"><img src="~/assets/images/avatars/unknown-profile.jpg" alt=""></span> <span class="account-summary pr-lg-4 d-none d-lg-block"><span class="account-name">@ViewData["user_name"]</span> <span class="account-description">@ViewData["user_permtype"]</span></span></button> <!-- .dropdown-menu -->
<div class="dropdown-menu">
<div class="dropdown-arrow d-lg-none" x-arrow=""></div>
<div class="dropdown-arrow ml-3 d-none d-lg-block"></div>
<h6 class="dropdown-header d-none d-sm-block d-lg-none"> Beni Arisandi </h6>@* <a class="dropdown-item" href="user-profile.html"><span class="dropdown-icon oi oi-person"></span> Profile</a> *@ <a class="dropdown-item" href="javascript: void();" onclick="logout()"><span class="dropdown-icon oi oi-account-logout"></span> Logout</a>
@* <div class="dropdown-divider"></div><a class="dropdown-item" href="#">Help Center</a> <a class="dropdown-item" href="#">Ask Forum</a> <a class="dropdown-item" href="#">Keyboard Shortcuts</a> *@
</div><!-- /.dropdown-menu -->
</div><!-- /.btn-account -->
</div><!-- /.top-bar-item -->
</div><!-- /.top-bar-list -->
</div><!-- /.top-bar -->
</header><!-- /.app-header -->
<!-- .app-aside -->
<aside class="app-aside app-aside-expand-md app-aside-light">
<!-- .aside-content -->
<div class="aside-content">
<!-- .aside-header -->
<header class="aside-header d-block d-md-none">
<!-- .btn-account -->
<button class="btn-account" type="button" data-toggle="collapse" data-target="#dropdown-aside"><span class="user-avatar user-avatar-lg"><img src="~/assets/images/avatars/unknown-profile.jpg" alt=""></span> <span class="account-icon"><span class="fa fa-caret-down fa-lg"></span></span> <span class="account-summary"><span class="account-name">@ViewData["user_name"]</span> <span class="account-description">@ViewData["user_permtype"]</span></span></button> <!-- /.btn-account -->
<!-- .dropdown-aside -->
<div id="dropdown-aside" class="dropdown-aside collapse">
<!-- dropdown-items -->
<div class="pb-3">
<a class="dropdown-item" href="user-profile.html"><span class="dropdown-icon oi oi-person"></span> Profile</a> <a class="dropdown-item" href="auth-signin-v1.html"><span class="dropdown-icon oi oi-account-logout"></span> Logout</a>
<div class="dropdown-divider"></div><a class="dropdown-item" href="#">Help Center</a> <a class="dropdown-item" href="#">Ask Forum</a> <a class="dropdown-item" href="#">Keyboard Shortcuts</a>
</div><!-- /dropdown-items -->
</div><!-- /.dropdown-aside -->
</header><!-- /.aside-header -->
<!-- .aside-menu -->
<div class="aside-menu overflow-hidden">
<!-- .stacked-menu -->
<nav id="stacked-menu" class="stacked-menu">
<!-- .menu -->
<ul class="menu">
<!-- .menu-item -->
<li class="menu-item">
<a href="~/Home/ProjectList" class="menu-link"><span class="menu-icon oi oi-box"></span> <span class="menu-text">報價單清單</span></a>
</li><!-- /.menu-item -->
<!-- .menu-item -->
<li class="menu-item has-child" id="authMenu" style='@ViewData["authMenu"]'>
<a href="#" class="menu-link"><span class="menu-icon oi oi-wrench"></span> <span class="menu-text">Auth</span></a> <!-- child menu -->
<ul class="menu">
<li class="menu-item">
<a href="~/Home/GroupList" class="menu-link">群組管理</a>
</li>
<li class="menu-item">
<a href="~/Home/UserList" class="menu-link">使用者管理</a>
</li>
</ul><!-- /child menu -->
</li><!-- /.menu-item -->
</ul><!-- /.menu -->
</nav><!-- /.stacked-menu -->
</div><!-- /.aside-menu -->
<!-- Skin changer -->
<footer class="aside-footer border-top p-2">
<button class="btn btn-light btn-block text-primary" data-toggle="skin"><span class="d-compact-menu-none">Night mode</span> <i class="fas fa-moon ml-1"></i></button>
</footer><!-- /Skin changer -->
</div><!-- /.aside-content -->
</aside><!-- /.app-aside -->
<!-- .app-main -->
<main class="app-main">
<!-- .wrapper -->
<div class="wrapper">
<!-- .page -->
<div class="page">
@RenderBody()
</div><!-- /.page -->
</div><!-- /.wrapper -->
<!-- .app-footer -->
<footer class="app-footer" style="display:none;">
<ul class="list-inline">
<li class="list-inline-item">
<a class="text-muted" href="#">Support</a>
</li>
<li class="list-inline-item">
<a class="text-muted" href="#">Help Center</a>
</li>
<li class="list-inline-item">
<a class="text-muted" href="#">Privacy</a>
</li>
<li class="list-inline-item">
<a class="text-muted" href="#">Terms of Service</a>
</li>
</ul>
<div class="copyright"> Copyright © 2023. All right reserved. </div>
</footer><!-- /.app-footer -->
</main><!-- /.app-main -->
</div><!-- /.app -->
<!-- BEGIN BASE JS -->
<script src="~/assets/vendor/jquery/jquery.min.js"></script>
<script src="~/assets/vendor/jquery.cookie/jquery.cookie.js"></script>
<script src="~/assets/javascript/custom/globalJS.js" asp-append-version="true"></script>
<script src="~/assets/vendor/popper.js/umd/popper.min.js"></script>
<script src="~/assets/vendor/bootstrap/js/bootstrap.min.js"></script> <!-- END BASE JS -->
<!-- BEGIN PLUGINS JS -->
<script src="~/assets/vendor/pace-progress/pace.min.js"></script>
<script src="~/assets/vendor/stacked-menu/js/stacked-menu.min.js"></script>
<script src="~/assets/vendor/perfect-scrollbar/perfect-scrollbar.min.js"></script>
<script src="~/assets/vendor/bootstrap-select/js/bootstrap-select.min.js"></script>
<script src="~/assets/vendor/masonry-layout/masonry.pkgd.min.js"></script>
<script src="~/assets/vendor/flatpickr/flatpickr.min.js"></script>
<script src="~/assets/vendor/flatpickr/plugins/monthSelect/index.js"></script>
<script src="~/assets/vendor/wnumb/wNumb.min.js"></script>
<script src="~/assets/vendor/nouisliderribute/nouislider.min.js"></script>
<script src="~/assets/vendor/blueimp-file-upload/js/vendor/jquery.ui.widget.js"></script>
<script src="~/assets/vendor/blueimp-load-image/js/load-image.all.min.js"></script>
<script src="~/assets/vendor/blueimp-canvas-to-blob/js/canvas-to-blob.min.js"></script>
<script src="~/assets/vendor/blueimp-file-upload/js/jquery.iframe-transport.js"></script>
<script src="~/assets/vendor/blueimp-file-upload/js/jquery.fileupload.js"></script>
<script src="~/assets/vendor/blueimp-file-upload/js/jquery.fileupload-process.js"></script>
<script src="~/assets/vendor/blueimp-file-upload/js/jquery.fileupload-image.js"></script>
<script src="~/assets/vendor/blueimp-file-upload/js/jquery.fileupload-audio.js"></script>
<script src="~/assets/vendor/blueimp-file-upload/js/jquery.fileupload-video.js"></script>
<script src="~/assets/vendor/blueimp-file-upload/js/jquery.fileupload-validate.js"></script>
<script src="~/assets/vendor/bootstrap-touchspin/jquery.bootstrap-touchspin.min.js"></script>
<script src="~/assets/vendor/easy-pie-chart/jquery.easypiechart.min.js"></script>
<script src="~/assets/vendor/chart.js/Chart.min.js"></script>
<script src="~/assets/vendor/sha256/sha256.js"></script>
<!-- END PLUGINS JS -->
<!-- BEGIN SELECT2-->
<script src="~/assets/vendor/handlebars/handlebars.min.js"></script>
<script src="~/assets/vendor/typeahead.js/typeahead.bundle.min.js"></script>
<script src="~/assets/vendor/select2/js/select2.full.min.js"></script>
<script src="~/assets/vendor/tributejs/tribute.min.js"></script>
<script src="~/assets/vendor/jquery.caret/jquery.caret.min.js"></script>
<script src="~/assets/vendor/at.js/js/jquery.atwho.min.js"></script>
<script src="~/assets/vendor/zxcvbn/zxcvbn.js"></script>
<script src="~/assets/vendor/vanilla-text-mask/vanillaTextMask.js"></script>
<script src="~/assets/vendor/text-mask-addons/textMaskAddons.js"></script>
<!-- END SELECT2-->
<!-- BEGIN THEME JS -->
<script src="~/assets/javascript/theme.min.js"></script> <!-- END THEME JS -->
<!-- BEGIN PAGE LEVEL JS -->
@RenderSection("Script", required: false)
<!-- END PAGE LEVEL JS -->
</body>
</html>

View File

@ -0,0 +1,2 @@
<script src="~/lib/jquery-validation/dist/jquery.validate.min.js"></script>
<script src="~/lib/jquery-validation-unobtrusive/jquery.validate.unobtrusive.min.js"></script>

View File

@ -0,0 +1,3 @@
@using QuotationMaker
@namespace QuotationMaker.Pages
@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers

3
Views/_ViewStart.cshtml Normal file
View File

@ -0,0 +1,3 @@
@{
//Layout = "_Layout";
}

View File

@ -0,0 +1,9 @@
{
"DetailedErrors": true,
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft.AspNetCore": "Warning"
}
}
}

20
appsettings.json Normal file
View File

@ -0,0 +1,20 @@
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft.AspNetCore": "Warning"
}
},
"AllowedHosts": "*",
"ConnectionStrings": {
"SQLConnectionString": "Data Source=sql.bremen.com.tw;Initial Catalog=quotationmaker_db;User ID=quotationmaker_db;Password=4Wa_453hl;Max Pool Size=100;",
"ElabConnectionString": "Data Source=sql.bremen.com.tw;database=elab;uid=elab;pwd=2#2k9Vfg",
"DBConnectionString": "Data Source=sql.bremen.com.tw;Initial Catalog=prm;User ID=prm;Password=y6U6x?t5;Max Pool Size=1250;"
},
"Admin": {
"uid": "system",
"id": "admin",
"pwd": "?Bremen!",
"perm": "system"
}
}

BIN
wwwroot/assets/.DS_Store vendored Normal file

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.3 KiB

View File

@ -0,0 +1,517 @@
{
"data": [
{
"id": "1",
"name": "Tiger Nixon",
"position": "System Architect",
"salary": "$320,800",
"start_date": "2011/04/25",
"office": "Edinburgh",
"extn": "5421"
},
{
"id": "2",
"name": "Garrett Winters",
"position": "Accountant",
"salary": "$170,750",
"start_date": "2011/07/25",
"office": "Tokyo",
"extn": "8422"
},
{
"id": "3",
"name": "Ashton Cox",
"position": "Junior Technical Author",
"salary": "$86,000",
"start_date": "2009/01/12",
"office": "San Francisco",
"extn": "1562"
},
{
"id": "4",
"name": "Cedric Kelly",
"position": "Senior Javascript Developer",
"salary": "$433,060",
"start_date": "2012/03/29",
"office": "Edinburgh",
"extn": "6224"
},
{
"id": "5",
"name": "Airi Satou",
"position": "Accountant",
"salary": "$162,700",
"start_date": "2008/11/28",
"office": "Tokyo",
"extn": "5407"
},
{
"id": "6",
"name": "Brielle Williamson",
"position": "Integration Specialist",
"salary": "$372,000",
"start_date": "2012/12/02",
"office": "New York",
"extn": "4804"
},
{
"id": "7",
"name": "Herrod Chandler",
"position": "Sales Assistant",
"salary": "$137,500",
"start_date": "2012/08/06",
"office": "San Francisco",
"extn": "9608"
},
{
"id": "8",
"name": "Rhona Davidson",
"position": "Integration Specialist",
"salary": "$327,900",
"start_date": "2010/10/14",
"office": "Tokyo",
"extn": "6200"
},
{
"id": "9",
"name": "Colleen Hurst",
"position": "Javascript Developer",
"salary": "$205,500",
"start_date": "2009/09/15",
"office": "San Francisco",
"extn": "2360"
},
{
"id": "10",
"name": "Sonya Frost",
"position": "Software Engineer",
"salary": "$103,600",
"start_date": "2008/12/13",
"office": "Edinburgh",
"extn": "1667"
},
{
"id": "11",
"name": "Jena Gaines",
"position": "Office Manager",
"salary": "$90,560",
"start_date": "2008/12/19",
"office": "London",
"extn": "3814"
},
{
"id": "12",
"name": "Quinn Flynn",
"position": "Support Lead",
"salary": "$342,000",
"start_date": "2013/03/03",
"office": "Edinburgh",
"extn": "9497"
},
{
"id": "13",
"name": "Charde Marshall",
"position": "Regional Director",
"salary": "$470,600",
"start_date": "2008/10/16",
"office": "San Francisco",
"extn": "6741"
},
{
"id": "14",
"name": "Haley Kennedy",
"position": "Senior Marketing Designer",
"salary": "$313,500",
"start_date": "2012/12/18",
"office": "London",
"extn": "3597"
},
{
"id": "15",
"name": "Tatyana Fitzpatrick",
"position": "Regional Director",
"salary": "$385,750",
"start_date": "2010/03/17",
"office": "London",
"extn": "1965"
},
{
"id": "16",
"name": "Michael Silva",
"position": "Marketing Designer",
"salary": "$198,500",
"start_date": "2012/11/27",
"office": "London",
"extn": "1581"
},
{
"id": "17",
"name": "Paul Byrd",
"position": "Chief Financial Officer (CFO)",
"salary": "$725,000",
"start_date": "2010/06/09",
"office": "New York",
"extn": "3059"
},
{
"id": "18",
"name": "Gloria Little",
"position": "Systems Administrator",
"salary": "$237,500",
"start_date": "2009/04/10",
"office": "New York",
"extn": "1721"
},
{
"id": "19",
"name": "Bradley Greer",
"position": "Software Engineer",
"salary": "$132,000",
"start_date": "2012/10/13",
"office": "London",
"extn": "2558"
},
{
"id": "20",
"name": "Dai Rios",
"position": "Personnel Lead",
"salary": "$217,500",
"start_date": "2012/09/26",
"office": "Edinburgh",
"extn": "2290"
},
{
"id": "21",
"name": "Jenette Caldwell",
"position": "Development Lead",
"salary": "$345,000",
"start_date": "2011/09/03",
"office": "New York",
"extn": "1937"
},
{
"id": "22",
"name": "Yuri Berry",
"position": "Chief Marketing Officer (CMO)",
"salary": "$675,000",
"start_date": "2009/06/25",
"office": "New York",
"extn": "6154"
},
{
"id": "23",
"name": "Caesar Vance",
"position": "Pre-Sales Support",
"salary": "$106,450",
"start_date": "2011/12/12",
"office": "New York",
"extn": "8330"
},
{
"id": "24",
"name": "Doris Wilder",
"position": "Sales Assistant",
"salary": "$85,600",
"start_date": "2010/09/20",
"office": "Sidney",
"extn": "3023"
},
{
"id": "25",
"name": "Angelica Ramos",
"position": "Chief Executive Officer (CEO)",
"salary": "$1,200,000",
"start_date": "2009/10/09",
"office": "London",
"extn": "5797"
},
{
"id": "26",
"name": "Gavin Joyce",
"position": "Developer",
"salary": "$92,575",
"start_date": "2010/12/22",
"office": "Edinburgh",
"extn": "8822"
},
{
"id": "27",
"name": "Jennifer Chang",
"position": "Regional Director",
"salary": "$357,650",
"start_date": "2010/11/14",
"office": "Singapore",
"extn": "9239"
},
{
"id": "28",
"name": "Brenden Wagner",
"position": "Software Engineer",
"salary": "$206,850",
"start_date": "2011/06/07",
"office": "San Francisco",
"extn": "1314"
},
{
"id": "29",
"name": "Fiona Green",
"position": "Chief Operating Officer (COO)",
"salary": "$850,000",
"start_date": "2010/03/11",
"office": "San Francisco",
"extn": "2947"
},
{
"id": "30",
"name": "Shou Itou",
"position": "Regional Marketing",
"salary": "$163,000",
"start_date": "2011/08/14",
"office": "Tokyo",
"extn": "8899"
},
{
"id": "31",
"name": "Michelle House",
"position": "Integration Specialist",
"salary": "$95,400",
"start_date": "2011/06/02",
"office": "Sidney",
"extn": "2769"
},
{
"id": "32",
"name": "Suki Burks",
"position": "Developer",
"salary": "$114,500",
"start_date": "2009/10/22",
"office": "London",
"extn": "6832"
},
{
"id": "33",
"name": "Prescott Bartlett",
"position": "Technical Author",
"salary": "$145,000",
"start_date": "2011/05/07",
"office": "London",
"extn": "3606"
},
{
"id": "34",
"name": "Gavin Cortez",
"position": "Team Leader",
"salary": "$235,500",
"start_date": "2008/10/26",
"office": "San Francisco",
"extn": "2860"
},
{
"id": "35",
"name": "Martena Mccray",
"position": "Post-Sales support",
"salary": "$324,050",
"start_date": "2011/03/09",
"office": "Edinburgh",
"extn": "8240"
},
{
"id": "36",
"name": "Unity Butler",
"position": "Marketing Designer",
"salary": "$85,675",
"start_date": "2009/12/09",
"office": "San Francisco",
"extn": "5384"
},
{
"id": "37",
"name": "Howard Hatfield",
"position": "Office Manager",
"salary": "$164,500",
"start_date": "2008/12/16",
"office": "San Francisco",
"extn": "7031"
},
{
"id": "38",
"name": "Hope Fuentes",
"position": "Secretary",
"salary": "$109,850",
"start_date": "2010/02/12",
"office": "San Francisco",
"extn": "6318"
},
{
"id": "39",
"name": "Vivian Harrell",
"position": "Financial Controller",
"salary": "$452,500",
"start_date": "2009/02/14",
"office": "San Francisco",
"extn": "9422"
},
{
"id": "40",
"name": "Timothy Mooney",
"position": "Office Manager",
"salary": "$136,200",
"start_date": "2008/12/11",
"office": "London",
"extn": "7580"
},
{
"id": "41",
"name": "Jackson Bradshaw",
"position": "Director",
"salary": "$645,750",
"start_date": "2008/09/26",
"office": "New York",
"extn": "1042"
},
{
"id": "42",
"name": "Olivia Liang",
"position": "Support Engineer",
"salary": "$234,500",
"start_date": "2011/02/03",
"office": "Singapore",
"extn": "2120"
},
{
"id": "43",
"name": "Bruno Nash",
"position": "Software Engineer",
"salary": "$163,500",
"start_date": "2011/05/03",
"office": "London",
"extn": "6222"
},
{
"id": "44",
"name": "Sakura Yamamoto",
"position": "Support Engineer",
"salary": "$139,575",
"start_date": "2009/08/19",
"office": "Tokyo",
"extn": "9383"
},
{
"id": "45",
"name": "Thor Walton",
"position": "Developer",
"salary": "$98,540",
"start_date": "2013/08/11",
"office": "New York",
"extn": "8327"
},
{
"id": "46",
"name": "Finn Camacho",
"position": "Support Engineer",
"salary": "$87,500",
"start_date": "2009/07/07",
"office": "San Francisco",
"extn": "2927"
},
{
"id": "47",
"name": "Serge Baldwin",
"position": "Data Coordinator",
"salary": "$138,575",
"start_date": "2012/04/09",
"office": "Singapore",
"extn": "8352"
},
{
"id": "48",
"name": "Zenaida Frank",
"position": "Software Engineer",
"salary": "$125,250",
"start_date": "2010/01/04",
"office": "New York",
"extn": "7439"
},
{
"id": "49",
"name": "Zorita Serrano",
"position": "Software Engineer",
"salary": "$115,000",
"start_date": "2012/06/01",
"office": "San Francisco",
"extn": "4389"
},
{
"id": "50",
"name": "Jennifer Acosta",
"position": "Junior Javascript Developer",
"salary": "$75,650",
"start_date": "2013/02/01",
"office": "Edinburgh",
"extn": "3431"
},
{
"id": "51",
"name": "Cara Stevens",
"position": "Sales Assistant",
"salary": "$145,600",
"start_date": "2011/12/06",
"office": "New York",
"extn": "3990"
},
{
"id": "52",
"name": "Hermione Butler",
"position": "Regional Director",
"salary": "$356,250",
"start_date": "2011/03/21",
"office": "London",
"extn": "1016"
},
{
"id": "53",
"name": "Lael Greer",
"position": "Systems Administrator",
"salary": "$103,500",
"start_date": "2009/02/27",
"office": "London",
"extn": "6733"
},
{
"id": "54",
"name": "Jonas Alexander",
"position": "Developer",
"salary": "$86,500",
"start_date": "2010/07/14",
"office": "San Francisco",
"extn": "8196"
},
{
"id": "55",
"name": "Shad Decker",
"position": "Regional Director",
"salary": "$183,000",
"start_date": "2008/11/13",
"office": "Edinburgh",
"extn": "6373"
},
{
"id": "56",
"name": "Michael Bruce",
"position": "Javascript Developer",
"salary": "$183,000",
"start_date": "2011/06/27",
"office": "Singapore",
"extn": "5384"
},
{
"id": "57",
"name": "Donna Snider",
"position": "Customer Support",
"salary": "$112,000",
"start_date": "2011/01/25",
"office": "New York",
"extn": "4226"
}
]
}

View File

@ -0,0 +1 @@
["Andorra","United Arab Emirates","Afghanistan","Antigua and Barbuda","Anguilla","Albania","Armenia","Angola","Antarctica","Argentina","American Samoa","Austria","Australia","Aruba","Åland","Azerbaijan","Bosnia and Herzegovina","Barbados","Bangladesh","Belgium","Burkina Faso","Bulgaria","Bahrain","Burundi","Benin","Saint Barthélemy","Bermuda","Brunei","Bolivia","Bonaire","Brazil","Bahamas","Bhutan","Bouvet Island","Botswana","Belarus","Belize","Canada","Cocos [Keeling] Islands","Congo","Central African Republic","Republic of the Congo","Switzerland","Ivory Coast","Cook Islands","Chile","Cameroon","China","Colombia","Costa Rica","Cuba","Cape Verde","Curacao","Christmas Island","Cyprus","Czechia","Germany","Djibouti","Denmark","Dominica","Dominican Republic","Algeria","Ecuador","Estonia","Egypt","Western Sahara","Eritrea","Spain","Ethiopia","Finland","Fiji","Falkland Islands","Micronesia","Faroe Islands","France","Gabon","United Kingdom","Grenada","Georgia","French Guiana","Guernsey","Ghana","Gibraltar","Greenland","Gambia","Guinea","Guadeloupe","Equatorial Guinea","Greece","South Georgia and the South Sandwich Islands","Guatemala","Guam","Guinea-Bissau","Guyana","Hong Kong","Heard Island and McDonald Islands","Honduras","Croatia","Haiti","Hungary","Indonesia","Ireland","Israel","Isle of Man","India","British Indian Ocean Territory","Iraq","Iran","Iceland","Italy","Jersey","Jamaica","Jordan","Japan","Kenya","Kyrgyzstan","Cambodia","Kiribati","Comoros","Saint Kitts and Nevis","North Korea","South Korea","Kuwait","Cayman Islands","Kazakhstan","Laos","Lebanon","Saint Lucia","Liechtenstein","Sri Lanka","Liberia","Lesotho","Lithuania","Luxembourg","Latvia","Libya","Morocco","Monaco","Moldova","Montenegro","Saint Martin","Madagascar","Marshall Islands","Macedonia","Mali","Myanmar [Burma]","Mongolia","Macao","Northern Mariana Islands","Martinique","Mauritania","Montserrat","Malta","Mauritius","Maldives","Malawi","Mexico","Malaysia","Mozambique","Namibia","New Caledonia","Niger","Norfolk Island","Nigeria","Nicaragua","Netherlands","Norway","Nepal","Nauru","Niue","New Zealand","Oman","Panama","Peru","French Polynesia","Papua New Guinea","Philippines","Pakistan","Poland","Saint Pierre and Miquelon","Pitcairn Islands","Puerto Rico","Palestine","Portugal","Palau","Paraguay","Qatar","Réunion","Romania","Serbia","Russia","Rwanda","Saudi Arabia","Solomon Islands","Seychelles","Sudan","Sweden","Singapore","Saint Helena","Slovenia","Svalbard and Jan Mayen","Slovakia","Sierra Leone","San Marino","Senegal","Somalia","Suriname","South Sudan","São Tomé and Príncipe","El Salvador","Sint Maarten","Syria","Swaziland","Turks and Caicos Islands","Chad","French Southern Territories","Togo","Thailand","Tajikistan","Tokelau","East Timor","Turkmenistan","Tunisia","Tonga","Turkey","Trinidad and Tobago","Tuvalu","Taiwan","Tanzania","Ukraine","Uganda","U.S. Minor Outlying Islands","United States","Uruguay","Uzbekistan","Vatican City","Saint Vincent and the Grenadines","Venezuela","British Virgin Islands","U.S. Virgin Islands","Vietnam","Vanuatu","Wallis and Futuna","Samoa","Kosovo","Yemen","Mayotte","South Africa","Zambia","Zimbabwe"]

View File

@ -0,0 +1,78 @@
[
{
"title": "Redesign website",
"start": "2020-04-01",
"textColor": "rgb(52, 108, 176)",
"backgroundColor": "rgba(52, 108, 176, .12)",
"borderColor": "rgb(52, 108, 176)"
},
{
"title": "Write new content",
"start": "2020-04-07",
"end": "2020-04-10",
"textColor": "rgb(0, 162, 138)",
"backgroundColor": "rgba(0, 162, 138, .12)",
"borderColor": "rgb(0, 162, 138)"
},
{
"id": 999,
"title": "Apply new styles",
"start": "2020-04-09T16:00:00",
"textColor": "rgb(95, 75, 139)",
"backgroundColor": "rgba(95, 75, 139, .12)",
"borderColor": "rgb(95, 75, 139)"
},
{
"id": 999,
"title": "Review",
"start": "2020-04-16T16:00:00",
"textColor": "rgb(0, 162, 138)",
"backgroundColor": "rgba(0, 162, 138, .12)",
"borderColor": "rgb(0, 162, 138)"
},
{
"title": "Conference",
"start": "2020-04-11",
"end": "2020-04-13",
"textColor": "rgb(1, 121, 168)",
"backgroundColor": "rgba(1, 121, 168, .12)",
"borderColor": "rgb(1, 121, 168)"
},
{
"title": "Meeting",
"start": "2020-04-12T10:30:00",
"end": "2020-04-12T12:30:00",
"textColor": "rgb(249, 172, 47)",
"backgroundColor": "rgba(249, 172, 47, .12)",
"borderColor": "rgb(249, 172, 47)"
},
{
"title": "Deploy",
"start": "2020-04-12T12:00:00",
"textColor": "rgb(0, 162, 138)",
"backgroundColor": "rgba(0, 162, 138, .12)",
"borderColor": "rgb(0, 162, 138)"
},
{
"title": "Meeting",
"start": "2020-04-25T14:30:00",
"textColor": "rgb(249, 172, 47)",
"backgroundColor": "rgba(249, 172, 47, .12)",
"borderColor": "rgb(249, 172, 47)"
},
{
"title": "Go live!",
"start": "2020-04-30T07:00:00",
"textColor": "rgb(183, 107, 163)",
"backgroundColor": "rgba(183, 107, 163, .12)",
"borderColor": "rgb(183, 107, 163)"
},
{
"title": "Click for Project",
"url": "page-project.html",
"start": "2020-04-28",
"textColor": "rgb(95, 75, 139)",
"backgroundColor": "rgba(95, 75, 139, .12)",
"borderColor": "rgb(95, 75, 139)"
}
]

View File

@ -0,0 +1,452 @@
[
{
"year": "1961",
"value": "West Side Story",
"tokens": [
"West",
"Side",
"Story"
]
},
{
"year": "1962",
"value": "Lawrence of Arabia",
"tokens": [
"Lawrence",
"of",
"Arabia"
]
},
{
"year": "1963",
"value": "Tom Jones",
"tokens": [
"Tom",
"Jones"
]
},
{
"year": "1964",
"value": "My Fair Lady",
"tokens": [
"My",
"Fair",
"Lady"
]
},
{
"year": "1965",
"value": "The Sound of Music",
"tokens": [
"The",
"Sound",
"of",
"Music"
]
},
{
"year": "1966",
"value": "A Man for All Seasons",
"tokens": [
"A",
"Man",
"for",
"All",
"Seasons"
]
},
{
"year": "1967",
"value": "In the Heat of the Night",
"tokens": [
"In",
"the",
"Heat",
"of",
"the",
"Night"
]
},
{
"year": "1968",
"value": "Oliver!",
"tokens": [
"Oliver!"
]
},
{
"year": "1969",
"value": "Midnight Cowboy",
"tokens": [
"Midnight",
"Cowboy"
]
},
{
"year": "1970",
"value": "Patton",
"tokens": [
"Patton"
]
},
{
"year": "1971",
"value": "The French Connection",
"tokens": [
"The",
"French",
"Connection"
]
},
{
"year": "1972",
"value": "The Godfather",
"tokens": [
"The",
"Godfather"
]
},
{
"year": "1973",
"value": "The Sting",
"tokens": [
"The",
"Sting"
]
},
{
"year": "1974",
"value": "The Godfather Part II",
"tokens": [
"The",
"Godfather",
"Part",
"II"
]
},
{
"year": "1975",
"value": "One Flew over the Cuckoo's Nest",
"tokens": [
"One",
"Flew",
"over",
"the",
"Cuckoo's",
"Nest"
]
},
{
"year": "1976",
"value": "Rocky",
"tokens": [
"Rocky"
]
},
{
"year": "1977",
"value": "Annie Hall",
"tokens": [
"Annie",
"Hall"
]
},
{
"year": "1978",
"value": "The Deer Hunter",
"tokens": [
"The",
"Deer",
"Hunter"
]
},
{
"year": "1979",
"value": "Kramer vs. Kramer",
"tokens": [
"Kramer",
"vs.",
"Kramer"
]
},
{
"year": "1980",
"value": "Ordinary People",
"tokens": [
"Ordinary",
"People"
]
},
{
"year": "1981",
"value": "Chariots of Fire",
"tokens": [
"Chariots",
"of",
"Fire"
]
},
{
"year": "1982",
"value": "Gandhi",
"tokens": [
"Gandhi"
]
},
{
"year": "1983",
"value": "Terms of Endearment",
"tokens": [
"Terms",
"of",
"Endearment"
]
},
{
"year": "1984",
"value": "Amadeus",
"tokens": [
"Amadeus"
]
},
{
"year": "1985",
"value": "Out of Africa",
"tokens": [
"Out",
"of",
"Africa"
]
},
{
"year": "1986",
"value": "Platoon",
"tokens": [
"Platoon"
]
},
{
"year": "1987",
"value": "The Last Emperor",
"tokens": [
"The",
"Last",
"Emperor"
]
},
{
"year": "1988",
"value": "Rain Man",
"tokens": [
"Rain",
"Man"
]
},
{
"year": "1989",
"value": "Driving Miss Daisy",
"tokens": [
"Driving",
"Miss",
"Daisy"
]
},
{
"year": "1990",
"value": "Dances With Wolves",
"tokens": [
"Dances",
"With",
"Wolves"
]
},
{
"year": "1991",
"value": "The Silence of the Lambs",
"tokens": [
"The",
"Silence",
"of",
"the",
"Lambs"
]
},
{
"year": "1992",
"value": "Unforgiven",
"tokens": [
"Unforgiven"
]
},
{
"year": "1993",
"value": "Schindlers List",
"tokens": [
"Schindlers",
"List"
]
},
{
"year": "1994",
"value": "Forrest Gump",
"tokens": [
"Forrest",
"Gump"
]
},
{
"year": "1995",
"value": "Braveheart",
"tokens": [
"Braveheart"
]
},
{
"year": "1996",
"value": "The English Patient",
"tokens": [
"The",
"English",
"Patient"
]
},
{
"year": "1997",
"value": "Titanic",
"tokens": [
"Titanic"
]
},
{
"year": "1998",
"value": "Shakespeare in Love",
"tokens": [
"Shakespeare",
"in",
"Love"
]
},
{
"year": "1999",
"value": "American Beauty",
"tokens": [
"American",
"Beauty"
]
},
{
"year": "2000",
"value": "Gladiator",
"tokens": [
"Gladiator"
]
},
{
"year": "2001",
"value": "A Beautiful Mind",
"tokens": [
"A",
"Beautiful",
"Mind"
]
},
{
"year": "2002",
"value": "Chicago",
"tokens": [
"Chicago"
]
},
{
"year": "2003",
"value": "The Lord of the Rings: The Return of the King",
"tokens": [
"The",
"Lord",
"of",
"the",
"Rings:",
"The",
"Return",
"of",
"the",
"King"
]
},
{
"year": "2004",
"value": "Million Dollar Baby",
"tokens": [
"Million",
"Dollar",
"Baby"
]
},
{
"year": "2005",
"value": "Crash",
"tokens": [
"Crash"
]
},
{
"year": "2006",
"value": "The Departed",
"tokens": [
"The",
"Departed"
]
},
{
"year": "2007",
"value": "No Country for Old Men",
"tokens": [
"No",
"Country",
"for",
"Old",
"Men"
]
},
{
"year": "2008",
"value": "Slumdog Millionaire",
"tokens": [
"Slumdog",
"Millionaire"
]
},
{
"year": "2009",
"value": "The Hurt Locker",
"tokens": [
"The",
"Hurt",
"Locker"
]
},
{
"year": "2010",
"value": "The King's Speech",
"tokens": [
"The",
"King's",
"Speech"
]
},
{
"year": "2011",
"value": "The Artist",
"tokens": [
"The",
"Artist"
]
},
{
"year": "2012",
"value": "Argo",
"tokens": [
"Argo"
]
}
]

View File

@ -0,0 +1,14 @@
[
{
"year": "1956",
"value": "Around the World in 80 Days",
"tokens": [
"Around",
"the",
"World",
"in",
"80",
"Days"
]
}
]

View File

@ -0,0 +1,14 @@
[
{
"year": "1956",
"value": "Around the World in 80 Days",
"tokens": [
"Around",
"the",
"World",
"in",
"80",
"Days"
]
}
]

View File

@ -0,0 +1,71 @@
[
{
"year": "1929/1930",
"value": "All Quiet on the Western Front",
"tokens": [
"All",
"Quiet",
"on",
"the",
"Western",
"Front"
]
},
{
"year": "1947",
"value": "Gentleman's Agreement",
"tokens": [
"Gentleman's",
"Agreement"
]
},
{
"year": "1949",
"value": "All the Kings Men",
"tokens": [
"All",
"the",
"Kings",
"Men"
]
},
{
"year": "1950",
"value": "All About Eve",
"tokens": [
"All",
"About",
"Eve"
]
},
{
"year": "1951",
"value": "An American in Paris",
"tokens": [
"An",
"American",
"in",
"Paris"
]
},
{
"year": "1956",
"value": "Around the World in 80 Days",
"tokens": [
"Around",
"the",
"World",
"in",
"80",
"Days"
]
},
{
"year": "1960",
"value": "The Apartment",
"tokens": [
"The",
"Apartment"
]
}
]

View File

@ -0,0 +1,11 @@
[
{
"year": "1950",
"value": "All About Eve",
"tokens": [
"All",
"About",
"Eve"
]
}
]

View File

@ -0,0 +1,11 @@
[
{
"year": "1950",
"value": "All About Eve",
"tokens": [
"All",
"About",
"Eve"
]
}
]

View File

@ -0,0 +1,11 @@
[
{
"year": "1950",
"value": "All About Eve",
"tokens": [
"All",
"About",
"Eve"
]
}
]

View File

@ -0,0 +1,11 @@
[
{
"year": "1950",
"value": "All About Eve",
"tokens": [
"All",
"About",
"Eve"
]
}
]

View File

@ -0,0 +1,10 @@
[
{
"year": "1947",
"value": "Gentleman's Agreement",
"tokens": [
"Gentleman's",
"Agreement"
]
}
]

View File

@ -0,0 +1,10 @@
[
{
"year": "1947",
"value": "Gentleman's Agreement",
"tokens": [
"Gentleman's",
"Agreement"
]
}
]

View File

@ -0,0 +1,10 @@
[
{
"year": "1947",
"value": "Gentleman's Agreement",
"tokens": [
"Gentleman's",
"Agreement"
]
}
]

View File

@ -0,0 +1,10 @@
[
{
"year": "1947",
"value": "Gentleman's Agreement",
"tokens": [
"Gentleman's",
"Agreement"
]
}
]

View File

@ -0,0 +1,10 @@
[
{
"year": "1947",
"value": "Gentleman's Agreement",
"tokens": [
"Gentleman's",
"Agreement"
]
}
]

View File

@ -0,0 +1,10 @@
[
{
"year": "1947",
"value": "Gentleman's Agreement",
"tokens": [
"Gentleman's",
"Agreement"
]
}
]

View File

@ -0,0 +1,10 @@
[
{
"year": "1947",
"value": "Gentleman's Agreement",
"tokens": [
"Gentleman's",
"Agreement"
]
}
]

View File

@ -0,0 +1,10 @@
[
{
"year": "1947",
"value": "Gentleman's Agreement",
"tokens": [
"Gentleman's",
"Agreement"
]
}
]

View File

@ -0,0 +1,33 @@
[
{
"year": "1929/1930",
"value": "All Quiet on the Western Front",
"tokens": [
"All",
"Quiet",
"on",
"the",
"Western",
"Front"
]
},
{
"year": "1949",
"value": "All the Kings Men",
"tokens": [
"All",
"the",
"Kings",
"Men"
]
},
{
"year": "1950",
"value": "All About Eve",
"tokens": [
"All",
"About",
"Eve"
]
}
]

View File

@ -0,0 +1,33 @@
[
{
"year": "1929/1930",
"value": "All Quiet on the Western Front",
"tokens": [
"All",
"Quiet",
"on",
"the",
"Western",
"Front"
]
},
{
"year": "1949",
"value": "All the Kings Men",
"tokens": [
"All",
"the",
"Kings",
"Men"
]
},
{
"year": "1950",
"value": "All About Eve",
"tokens": [
"All",
"About",
"Eve"
]
}
]

View File

@ -0,0 +1,12 @@
[
{
"year": "1951",
"value": "An American in Paris",
"tokens": [
"An",
"American",
"in",
"Paris"
]
}
]

View File

@ -0,0 +1,12 @@
[
{
"year": "1951",
"value": "An American in Paris",
"tokens": [
"An",
"American",
"in",
"Paris"
]
}
]

View File

@ -0,0 +1,12 @@
[
{
"year": "1951",
"value": "An American in Paris",
"tokens": [
"An",
"American",
"in",
"Paris"
]
}
]

View File

@ -0,0 +1,12 @@
[
{
"year": "1951",
"value": "An American in Paris",
"tokens": [
"An",
"American",
"in",
"Paris"
]
}
]

View File

@ -0,0 +1,12 @@
[
{
"year": "1951",
"value": "An American in Paris",
"tokens": [
"An",
"American",
"in",
"Paris"
]
}
]

View File

@ -0,0 +1,12 @@
[
{
"year": "1951",
"value": "An American in Paris",
"tokens": [
"An",
"American",
"in",
"Paris"
]
}
]

View File

@ -0,0 +1,12 @@
[
{
"year": "1951",
"value": "An American in Paris",
"tokens": [
"An",
"American",
"in",
"Paris"
]
}
]

View File

@ -0,0 +1,12 @@
[
{
"year": "1951",
"value": "An American in Paris",
"tokens": [
"An",
"American",
"in",
"Paris"
]
}
]

View File

@ -0,0 +1,10 @@
[
{
"year": "1960",
"value": "The Apartment",
"tokens": [
"The",
"Apartment"
]
}
]

View File

@ -0,0 +1,10 @@
[
{
"year": "1960",
"value": "The Apartment",
"tokens": [
"The",
"Apartment"
]
}
]

View File

@ -0,0 +1,10 @@
[
{
"year": "1960",
"value": "The Apartment",
"tokens": [
"The",
"Apartment"
]
}
]

View File

@ -0,0 +1,10 @@
[
{
"year": "1960",
"value": "The Apartment",
"tokens": [
"The",
"Apartment"
]
}
]

View File

@ -0,0 +1,10 @@
[
{
"year": "1960",
"value": "The Apartment",
"tokens": [
"The",
"Apartment"
]
}
]

View File

@ -0,0 +1,10 @@
[
{
"year": "1960",
"value": "The Apartment",
"tokens": [
"The",
"Apartment"
]
}
]

View File

@ -0,0 +1,10 @@
[
{
"year": "1960",
"value": "The Apartment",
"tokens": [
"The",
"Apartment"
]
}
]

View File

@ -0,0 +1,10 @@
[
{
"year": "1960",
"value": "The Apartment",
"tokens": [
"The",
"Apartment"
]
}
]

View File

@ -0,0 +1,14 @@
[
{
"year": "1956",
"value": "Around the World in 80 Days",
"tokens": [
"Around",
"the",
"World",
"in",
"80",
"Days"
]
}
]

View File

@ -0,0 +1,14 @@
[
{
"year": "1956",
"value": "Around the World in 80 Days",
"tokens": [
"Around",
"the",
"World",
"in",
"80",
"Days"
]
}
]

View File

@ -0,0 +1,14 @@
[
{
"year": "1956",
"value": "Around the World in 80 Days",
"tokens": [
"Around",
"the",
"World",
"in",
"80",
"Days"
]
}
]

View File

@ -0,0 +1,14 @@
[
{
"year": "1956",
"value": "Around the World in 80 Days",
"tokens": [
"Around",
"the",
"World",
"in",
"80",
"Days"
]
}
]

View File

@ -0,0 +1,14 @@
[
{
"year": "1956",
"value": "Around the World in 80 Days",
"tokens": [
"Around",
"the",
"World",
"in",
"80",
"Days"
]
}
]

View File

@ -0,0 +1,52 @@
[
{
"year": "1928/1929",
"value": "The Broadway Melody",
"tokens": [
"The",
"Broadway",
"Melody"
]
},
{
"year": "1935",
"value": "Mutiny on the Bounty",
"tokens": [
"Mutiny",
"on",
"the",
"Bounty"
]
},
{
"year": "1946",
"value": "The Best Years of Our Lives",
"tokens": [
"The",
"Best",
"Years",
"of",
"Our",
"Lives"
]
},
{
"year": "1957",
"value": "The Bridge on the River Kwai",
"tokens": [
"The",
"Bridge",
"on",
"the",
"River",
"Kwai"
]
},
{
"year": "1959",
"value": "Ben-Hur",
"tokens": [
"Ben-Hur"
]
}
]

View File

@ -0,0 +1,21 @@
[
{
"year": "1946",
"value": "The Best Years of Our Lives",
"tokens": [
"The",
"Best",
"Years",
"of",
"Our",
"Lives"
]
},
{
"year": "1959",
"value": "Ben-Hur",
"tokens": [
"Ben-Hur"
]
}
]

View File

@ -0,0 +1,9 @@
[
{
"year": "1959",
"value": "Ben-Hur",
"tokens": [
"Ben-Hur"
]
}
]

View File

@ -0,0 +1,9 @@
[
{
"year": "1959",
"value": "Ben-Hur",
"tokens": [
"Ben-Hur"
]
}
]

View File

@ -0,0 +1,9 @@
[
{
"year": "1959",
"value": "Ben-Hur",
"tokens": [
"Ben-Hur"
]
}
]

View File

@ -0,0 +1,9 @@
[
{
"year": "1959",
"value": "Ben-Hur",
"tokens": [
"Ben-Hur"
]
}
]

View File

@ -0,0 +1,14 @@
[
{
"year": "1946",
"value": "The Best Years of Our Lives",
"tokens": [
"The",
"Best",
"Years",
"of",
"Our",
"Lives"
]
}
]

View File

@ -0,0 +1,14 @@
[
{
"year": "1946",
"value": "The Best Years of Our Lives",
"tokens": [
"The",
"Best",
"Years",
"of",
"Our",
"Lives"
]
}
]

View File

@ -0,0 +1,12 @@
[
{
"year": "1935",
"value": "Mutiny on the Bounty",
"tokens": [
"Mutiny",
"on",
"the",
"Bounty"
]
}
]

View File

@ -0,0 +1,12 @@
[
{
"year": "1935",
"value": "Mutiny on the Bounty",
"tokens": [
"Mutiny",
"on",
"the",
"Bounty"
]
}
]

View File

@ -0,0 +1,12 @@
[
{
"year": "1935",
"value": "Mutiny on the Bounty",
"tokens": [
"Mutiny",
"on",
"the",
"Bounty"
]
}
]

View File

@ -0,0 +1,12 @@
[
{
"year": "1935",
"value": "Mutiny on the Bounty",
"tokens": [
"Mutiny",
"on",
"the",
"Bounty"
]
}
]

View File

@ -0,0 +1,12 @@
[
{
"year": "1935",
"value": "Mutiny on the Bounty",
"tokens": [
"Mutiny",
"on",
"the",
"Bounty"
]
}
]

View File

@ -0,0 +1,23 @@
[
{
"year": "1928/1929",
"value": "The Broadway Melody",
"tokens": [
"The",
"Broadway",
"Melody"
]
},
{
"year": "1957",
"value": "The Bridge on the River Kwai",
"tokens": [
"The",
"Bridge",
"on",
"the",
"River",
"Kwai"
]
}
]

View File

@ -0,0 +1,14 @@
[
{
"year": "1957",
"value": "The Bridge on the River Kwai",
"tokens": [
"The",
"Bridge",
"on",
"the",
"River",
"Kwai"
]
}
]

View File

@ -0,0 +1,14 @@
[
{
"year": "1957",
"value": "The Bridge on the River Kwai",
"tokens": [
"The",
"Bridge",
"on",
"the",
"River",
"Kwai"
]
}
]

View File

@ -0,0 +1,14 @@
[
{
"year": "1957",
"value": "The Bridge on the River Kwai",
"tokens": [
"The",
"Bridge",
"on",
"the",
"River",
"Kwai"
]
}
]

View File

@ -0,0 +1,14 @@
[
{
"year": "1957",
"value": "The Bridge on the River Kwai",
"tokens": [
"The",
"Bridge",
"on",
"the",
"River",
"Kwai"
]
}
]

View File

@ -0,0 +1,11 @@
[
{
"year": "1928/1929",
"value": "The Broadway Melody",
"tokens": [
"The",
"Broadway",
"Melody"
]
}
]

View File

@ -0,0 +1,11 @@
[
{
"year": "1928/1929",
"value": "The Broadway Melody",
"tokens": [
"The",
"Broadway",
"Melody"
]
}
]

View File

@ -0,0 +1,11 @@
[
{
"year": "1928/1929",
"value": "The Broadway Melody",
"tokens": [
"The",
"Broadway",
"Melody"
]
}
]

View File

@ -0,0 +1,11 @@
[
{
"year": "1928/1929",
"value": "The Broadway Melody",
"tokens": [
"The",
"Broadway",
"Melody"
]
}
]

View File

@ -0,0 +1,11 @@
[
{
"year": "1928/1929",
"value": "The Broadway Melody",
"tokens": [
"The",
"Broadway",
"Melody"
]
}
]

View File

@ -0,0 +1,11 @@
[
{
"year": "1928/1929",
"value": "The Broadway Melody",
"tokens": [
"The",
"Broadway",
"Melody"
]
}
]

View File

@ -0,0 +1,35 @@
[
{
"year": "1930/1931",
"value": "Cimarron",
"tokens": [
"Cimarron"
]
},
{
"year": "1932/1933",
"value": "Cavalcade",
"tokens": [
"Cavalcade"
]
},
{
"year": "1938",
"value": "You Can't Take It with You",
"tokens": [
"You",
"Can't",
"Take",
"It",
"with",
"You"
]
},
{
"year": "1943",
"value": "Casablanca",
"tokens": [
"Casablanca"
]
}
]

View File

@ -0,0 +1,28 @@
[
{
"year": "1932/1933",
"value": "Cavalcade",
"tokens": [
"Cavalcade"
]
},
{
"year": "1938",
"value": "You Can't Take It with You",
"tokens": [
"You",
"Can't",
"Take",
"It",
"with",
"You"
]
},
{
"year": "1943",
"value": "Casablanca",
"tokens": [
"Casablanca"
]
}
]

View File

@ -0,0 +1,14 @@
[
{
"year": "1938",
"value": "You Can't Take It with You",
"tokens": [
"You",
"Can't",
"Take",
"It",
"with",
"You"
]
}
]

View File

@ -0,0 +1,14 @@
[
{
"year": "1938",
"value": "You Can't Take It with You",
"tokens": [
"You",
"Can't",
"Take",
"It",
"with",
"You"
]
}
]

Some files were not shown because too many files have changed in this diff Show More