First Commit (API Project)

This commit is contained in:
2025-07-17 10:05:47 +09:00
commit ad702d5ccf
371 changed files with 141373 additions and 0 deletions

18
.editorconfig Normal file
View File

@@ -0,0 +1,18 @@
root = true
[*]
charset = utf-8
end_of_line = lf
indent_size = 4
indent_style = space
insert_final_newline = true
trim_trailing_whitespace = true
[*.md]
trim_trailing_whitespace = false
[*.{yml,yaml}]
indent_size = 2
[docker-compose.yml]
indent_size = 4

11
.gitattributes vendored Normal file
View File

@@ -0,0 +1,11 @@
* text=auto eol=lf
*.blade.php diff=html
*.css diff=css
*.html diff=html
*.md diff=markdown
*.php diff=php
/.github export-ignore
CHANGELOG.md export-ignore
.styleci.yml export-ignore

165
.gitignore vendored Normal file
View File

@@ -0,0 +1,165 @@
############################################
# Laravel
############################################
/vendor/
/node_modules/
/bootstrap/cache/
/storage/*.key
/storage/app/*
/storage/framework/*
/storage/logs/*
!storage/.gitignore
.env
.env.*
.phpunit.result.cache
Homestead.yaml
Homestead.json
npm-debug.log
yarn-error.log
vite.config.js
vite.config.ts
public/storage
public/hot
public/mix-manifest.json
public/build/
/storage/pail/
public/js/*.map
public/css/*.map
############################################
# CodeIgniter (CI3 or CI4)
############################################
/system/
application/cache/*
application/logs/*
writable/cache/
writable/logs/
writable/session/
writable/uploads/
!application/cache/index.html
!application/logs/index.html
############################################
# IDE - PhpStorm
############################################
.idea/
/*.iml
*.iws
*.ipr
############################################
# IDE - VS Code
############################################
.vscode/
############################################
# IDE - Cursor AI
############################################
.cursor/
############################################
# OS & 에디터 임시 파일
############################################
.DS_Store
Thumbs.db
ehthumbs.db
desktop.ini
*.swp
*.swo
*.tmp
*.bak
*.old
*.orig
############################################
# 로그, 백업, 덤프
############################################
*.log
*.sql
*.sqlite
*.db
*.tar
*.gz
*.zip
*.7z
*.bak
*.backup
*.old
# 프로젝트 내 백업 폴더
/backup/
/backups/
############################################
# 이미지, 문서, 동영상 등 업로드 제외
*.jpg
*.jpeg
*.png
*.gif
*.bmp
*.svg
*.webp
*.ico
*.pdf
*.doc
*.docx
*.xls
*.xlsx
*.ppt
*.pptx
*.hwp
*.mp3
*.wav
*.ogg
*.mp4
*.avi
*.mov
*.wmv
*.mkv
############################################
# Composer / Node 관련
############################################
composer.lock
package-lock.json
pnpm-lock.yaml
############################################
# JetBrains Fleet / Laravel Nova / Zed IDE
############################################
/.fleet/
/.nova/
/.zed/
############################################
# PHP 도구 및 설정 파일
############################################
/.phpactor.json
/auth.json
/.phpunit.cache
############################################
# 기타
############################################
.env.local
.env.backup
*.cache
*.coverage
*.out
*.pid
*.seed
*.seed.php
# 모든 위치의 data 폴더 내부 파일 무시
**/data/*
# 단, 폴더 자체는 추적 (비어 있어도 gitkeep을 위해)
!**/data/
# 그리고 .gitkeep은 예외로 추적
!**/data/.gitkeep

66
README.md Normal file
View File

@@ -0,0 +1,66 @@
<p align="center"><a href="https://laravel.com" target="_blank"><img src="https://raw.githubusercontent.com/laravel/art/master/logo-lockup/5%20SVG/2%20CMYK/1%20Full%20Color/laravel-logolockup-cmyk-red.svg" width="400" alt="Laravel Logo"></a></p>
<p align="center">
<a href="https://github.com/laravel/framework/actions"><img src="https://github.com/laravel/framework/workflows/tests/badge.svg" alt="Build Status"></a>
<a href="https://packagist.org/packages/laravel/framework"><img src="https://img.shields.io/packagist/dt/laravel/framework" alt="Total Downloads"></a>
<a href="https://packagist.org/packages/laravel/framework"><img src="https://img.shields.io/packagist/v/laravel/framework" alt="Latest Stable Version"></a>
<a href="https://packagist.org/packages/laravel/framework"><img src="https://img.shields.io/packagist/l/laravel/framework" alt="License"></a>
</p>
## About Laravel
Laravel is a web application framework with expressive, elegant syntax. We believe development must be an enjoyable and creative experience to be truly fulfilling. Laravel takes the pain out of development by easing common tasks used in many web projects, such as:
- [Simple, fast routing engine](https://laravel.com/docs/routing).
- [Powerful dependency injection container](https://laravel.com/docs/container).
- Multiple back-ends for [session](https://laravel.com/docs/session) and [cache](https://laravel.com/docs/cache) storage.
- Expressive, intuitive [database ORM](https://laravel.com/docs/eloquent).
- Database agnostic [schema migrations](https://laravel.com/docs/migrations).
- [Robust background job processing](https://laravel.com/docs/queues).
- [Real-time event broadcasting](https://laravel.com/docs/broadcasting).
Laravel is accessible, powerful, and provides tools required for large, robust applications.
## Learning Laravel
Laravel has the most extensive and thorough [documentation](https://laravel.com/docs) and video tutorial library of all modern web application frameworks, making it a breeze to get started with the framework.
You may also try the [Laravel Bootcamp](https://bootcamp.laravel.com), where you will be guided through building a modern Laravel application from scratch.
If you don't feel like reading, [Laracasts](https://laracasts.com) can help. Laracasts contains thousands of video tutorials on a range of topics including Laravel, modern PHP, unit testing, and JavaScript. Boost your skills by digging into our comprehensive video library.
## Laravel Sponsors
We would like to extend our thanks to the following sponsors for funding Laravel development. If you are interested in becoming a sponsor, please visit the [Laravel Partners program](https://partners.laravel.com).
### Premium Partners
- **[Vehikl](https://vehikl.com/)**
- **[Tighten Co.](https://tighten.co)**
- **[WebReinvent](https://webreinvent.com/)**
- **[Kirschbaum Development Group](https://kirschbaumdevelopment.com)**
- **[64 Robots](https://64robots.com)**
- **[Curotec](https://www.curotec.com/services/technologies/laravel/)**
- **[Cyber-Duck](https://cyber-duck.co.uk)**
- **[DevSquad](https://devsquad.com/hire-laravel-developers)**
- **[Jump24](https://jump24.co.uk)**
- **[Redberry](https://redberry.international/laravel/)**
- **[Active Logic](https://activelogic.com)**
- **[byte5](https://byte5.de)**
- **[OP.GG](https://op.gg)**
## Contributing
Thank you for considering contributing to the Laravel framework! The contribution guide can be found in the [Laravel documentation](https://laravel.com/docs/contributions).
## Code of Conduct
In order to ensure that the Laravel community is welcoming to all, please review and abide by the [Code of Conduct](https://laravel.com/docs/contributions#code-of-conduct).
## Security Vulnerabilities
If you discover a security vulnerability within Laravel, please send an e-mail to Taylor Otwell via [taylor@laravel.com](mailto:taylor@laravel.com). All security vulnerabilities will be promptly addressed.
## License
The Laravel framework is open-sourced software licensed under the [MIT license](https://opensource.org/licenses/MIT).

View File

@@ -0,0 +1,39 @@
<?php
namespace App\Actions\Fortify;
use App\Models\User;
use Illuminate\Support\Facades\Hash;
use Illuminate\Support\Facades\Validator;
use Laravel\Fortify\Contracts\CreatesNewUsers;
use Laravel\Jetstream\Jetstream;
class CreateNewUser implements CreatesNewUsers
{
use PasswordValidationRules;
/**
* Validate and create a newly registered user.
*
* @param array<string, string> $input
*/
public function create(array $input): User
{
Validator::make($input, [
'USER_ID' => ['required', 'string', 'max:30', 'unique:SITE_USER_INFO,USER_ID'],
'USER_PWD' => ['required', 'string', 'min:8'],
'USER_EMAIL' => ['nullable', 'string', 'email', 'max:40'],
'USER_NCNM' => ['nullable', 'string', 'max:50'],
])->validate();
return User::create([
'USER_ID' => $input['USER_ID'],
'USER_PWD' => Hash::make($input['USER_PWD']), // 비밀번호 암호화 저장
'USER_NCNM' => $input['USER_NCNM'] ?? null,
'USER_EMAIL' => $input['USER_EMAIL'] ?? null,
'USER_HP' => $input['USER_HP'] ?? null,
'USER_STATUS' => '01', // 기본적으로 활성화 상태
'REG_DTTM' => now(), // 등록 날짜 자동 설정
]);
}
}

View File

@@ -0,0 +1,18 @@
<?php
namespace App\Actions\Fortify;
use Illuminate\Validation\Rules\Password;
trait PasswordValidationRules
{
/**
* Get the validation rules used to validate passwords.
*
* @return array<int, \Illuminate\Contracts\Validation\Rule|array<mixed>|string>
*/
protected function passwordRules(): array
{
return ['required', 'string', Password::default(), 'confirmed'];
}
}

View File

@@ -0,0 +1,29 @@
<?php
namespace App\Actions\Fortify;
use App\Models\User;
use Illuminate\Support\Facades\Hash;
use Illuminate\Support\Facades\Validator;
use Laravel\Fortify\Contracts\ResetsUserPasswords;
class ResetUserPassword implements ResetsUserPasswords
{
use PasswordValidationRules;
/**
* Validate and reset the user's forgotten password.
*
* @param array<string, string> $input
*/
public function reset(User $user, array $input): void
{
Validator::make($input, [
'password' => $this->passwordRules(),
])->validate();
$user->forceFill([
'password' => Hash::make($input['password']),
])->save();
}
}

View File

@@ -0,0 +1,32 @@
<?php
namespace App\Actions\Fortify;
use App\Models\User;
use Illuminate\Support\Facades\Hash;
use Illuminate\Support\Facades\Validator;
use Laravel\Fortify\Contracts\UpdatesUserPasswords;
class UpdateUserPassword implements UpdatesUserPasswords
{
use PasswordValidationRules;
/**
* Validate and update the user's password.
*
* @param array<string, string> $input
*/
public function update(User $user, array $input): void
{
Validator::make($input, [
'current_password' => ['required', 'string', 'current_password:web'],
'password' => $this->passwordRules(),
], [
'current_password.current_password' => __('The provided password does not match your current password.'),
])->validateWithBag('updatePassword');
$user->forceFill([
'password' => Hash::make($input['password']),
])->save();
}
}

View File

@@ -0,0 +1,56 @@
<?php
namespace App\Actions\Fortify;
use App\Models\User;
use Illuminate\Contracts\Auth\MustVerifyEmail;
use Illuminate\Support\Facades\Validator;
use Illuminate\Validation\Rule;
use Laravel\Fortify\Contracts\UpdatesUserProfileInformation;
class UpdateUserProfileInformation implements UpdatesUserProfileInformation
{
/**
* Validate and update the given user's profile information.
*
* @param array<string, mixed> $input
*/
public function update(User $user, array $input): void
{
Validator::make($input, [
'name' => ['required', 'string', 'max:255'],
'email' => ['required', 'email', 'max:255', Rule::unique('users')->ignore($user->id)],
'photo' => ['nullable', 'mimes:jpg,jpeg,png', 'max:1024'],
])->validateWithBag('updateProfileInformation');
if (isset($input['photo'])) {
$user->updateProfilePhoto($input['photo']);
}
if ($input['email'] !== $user->email &&
$user instanceof MustVerifyEmail) {
$this->updateVerifiedUser($user, $input);
} else {
$user->forceFill([
'name' => $input['name'],
'email' => $input['email'],
])->save();
}
}
/**
* Update the given verified user's profile information.
*
* @param array<string, string> $input
*/
protected function updateVerifiedUser(User $user, array $input): void
{
$user->forceFill([
'name' => $input['name'],
'email' => $input['email'],
'email_verified_at' => null,
])->save();
$user->sendEmailVerificationNotification();
}
}

View File

@@ -0,0 +1,19 @@
<?php
namespace App\Actions\Jetstream;
use App\Models\User;
use Laravel\Jetstream\Contracts\DeletesUsers;
class DeleteUser implements DeletesUsers
{
/**
* Delete the given user.
*/
public function delete(User $user): void
{
$user->deleteProfilePhoto();
$user->tokens->each->delete();
$user->delete();
}
}

131
app/Helpers/ApiResponse.php Normal file
View File

@@ -0,0 +1,131 @@
<?php
namespace App\Helpers;
use Illuminate\Support\Facades\DB;
use Illuminate\Http\JsonResponse;
class ApiResponse
{
function normalizeFiles(array $laravelFiles): array {
$files = ['name' => [], 'type' => [], 'tmp_name' => [], 'size' => [], 'fileType' => []];
foreach ($laravelFiles as $file) {
$files['name'][] = $file->getClientOriginalName();
$files['type'][] = $file->getClientMimeType();
$files['tmp_name'][] = $file->getPathname();
$files['size'][] = $file->getSize();
$files['fileType'][] = '';
}
return $files;
}
# DebugQuery Helper
public static function debugQueryLog(): array
{
$logs = DB::getQueryLog();
return collect($logs)->map(function ($log) {
$query = $log['query'];
foreach ($log['bindings'] as $binding) {
$binding = is_numeric($binding) ? $binding : "'" . addslashes($binding) . "'";
$query = preg_replace('/\\?/', $binding, $query, 1);
}
// \n 제거
$query = str_replace(["\n", "\r"], ' ', $query);
return trim($query);
})->toArray();
}
# ApiResponse Helper
public static function success(
$data = null,
string $message = '요청 성공',
array $debug = []
): JsonResponse {
$response = [
'success' => true,
'message' => $message,
'data' => $data,
];
if(!empty($debug)) $response['query'] = $debug;
return response()->json($response);
}
public static function error(
string $message = '요청 실패',
int $code = 400,
array $error = []
): JsonResponse {
return response()->json([
'success' => false,
'message' => $message,
'error' => [
'code' => $code,
'details' => $error['details'] ?? null,
],
], $code);
}
public static function validate(
bool $condition,
string $message = 'Validation failed',
int $code = 422,
array $extra = []
): ?JsonResponse {
return $condition ? null : self::error($message, $code, $extra);
}
public static function response($type = '', $query = '', $debug = false, $key = ''): array
{
if ($debug && $type != 'success') DB::enableQueryLog(); // 쿼리 추적
$result = match ($type) {
'get' => $key ? $query->get()->keyBy($key) : $query->get(),
'getSub' => $query->get(),
'count' => $query->count(),
'first' => $query->first(),
'success' => 'Success',
'result' => $query,
default => null,
};
if($type=='getSub'){
$array = $result->map(function ($item) {
return (array) $item;
})->toArray();
foreach ($array as $row) {
$data[$row[$key]][] = $row;
}
$result = $data ?? [];
}
$response['data'] = $result;
$response['query'] = ($debug) ? self::debugQueryLog() : [];
return $response;
}
public static function handle(
callable $callback,
string $successMessage = '요청 성공',
string $errorMessage = '요청 실패'
): JsonResponse {
try {
$result = $callback();
if ($result instanceof JsonResponse) {
return $result;
}
return self::success(
$result['data'] ?? null, $successMessage, $result['query'] ?? []
);
} catch (\Throwable $e) {
return self::error($errorMessage, 500, [
'details' => $e->getMessage(),
]);
}
}
}

View File

@@ -0,0 +1,37 @@
<?php
namespace App\Http\Controllers\Api;
use App\Http\Controllers\Controller;
use Illuminate\Http\Request;
use App\Helpers\ApiResponse;
use App\Models\SiteAdmin;
class AdminApiController extends Controller
{
/* /**
* @OA\Post(
* path="/api/admin/list",
* summary="관리자 리스트",
* tags={"Admin"},
* security={{"ApiKeyAuth":{}}},
* @OA\RequestBody(
* required=true,
* @OA\JsonContent(
* required={"user_token"},
* @OA\Property(property="user_token", type="string", example="XXXXXXX")
* )
* ),
* @OA\Response(response=200, description="성공"),
* @OA\Response(response=401, description="실패")
* )
*/
public function list(Request $request)
{
return ApiResponse::handle(function () use ($request) {
$admins = new SiteAdmin;
return ApiResponse::response('get', $admins, $request->debug);
}, '관리자 목록 조회 성공', '관리자 목록 조회 실패');
}
}

View File

@@ -0,0 +1,144 @@
<?php
namespace App\Http\Controllers\Api;
use App\Models\Member;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Hash;
use Illuminate\Support\Str;
use App\Http\Controllers\Controller;
use App\Models\User;
/**
* @OA\Info(
* version="1.0.0",
* title="SAM API Documentation",
* description="SAM(Semi-Automatics Management) API 입니다.",
* @OA\Contact(
* email="shine1324@gmail.com"
* )
* )
*
* @OA\Server(
* url="https://api.5130.co.kr",
* description="SAM API 서버"
* )
*/
class ApiController extends Controller
{
/**
* @OA\Get(
* path="/api/debug-apikey",
* tags={"API Key 인증"},
* summary="API Key 인증 확인",
* security={{"ApiKeyAuth":{}}},
* @OA\Response(
* response=200,
* description="API Key 인증 성공"
* ),
* @OA\Response(
* response=401,
* description="인증 실패"
* )
* )
*/
public function debugApikey()
{
return response()->json(['message' => 'API Key 인증 성공']);
}
/**
* @OA\Post(
* path="/api/login",
* summary="회원 토큰 정보확인",
* tags={"Auth"},
* @OA\RequestBody(
* required=true,
* @OA\JsonContent(
* required={"USER_ID", "USER_PWD"},
* @OA\Property(property="USER_ID", type="string", example="admin"),
* @OA\Property(property="USER_PWD", type="string", example="1234")
* )
* ),
* @OA\Response(
* response=200,
* description="로그인 성공",
* @OA\JsonContent(
* @OA\Property(property="message", type="string"),
* @OA\Property(property="USER_TOKEN", type="string")
* )
* ),
* @OA\Response(response=401, description="로그인 실패")
* )
*/
public function login(Request $request)
{
$userId = $request->input('user_id');
$userPwd = $request->input('user_pwd');
if (!$userId || !$userPwd) {
return response()->json(['error' => '아이디 또는 비밀번호 누락'], 400);
}
$user = Member::where('mb_id', $userId)->first();
if (!$user) {
return response()->json(['error' => '사용자를 찾을 수 없습니다.'], 404);
}
$isValid = false;
if (Str::startsWith($user->mb_pass, '$2y$')) {
// bcrypt로 해싱된 경우
$isValid = Hash::check($userPwd, $user->mb_pass);
} else {
// sha256으로 해싱된 경우
$isValid = strtoupper(hash('sha256', $userPwd)) === strtoupper($user->mb_pass);
}
if (!$isValid) {
return response()->json(['error' => '아이디 또는 비밀번호가 올바르지 않습니다.'], 401);
}
// 선택: DB에 신규 token 저장
$USER_TOKEN = hash('sha256', $user->mb_id.date('YmdHis'));
$user->remember_token = $USER_TOKEN;
$user->save();
return response()->json([
'message' => '로그인 성공',
'USER_TOKEN' => $user->USER_TOKEN,
]);
}
/**
* @OA\Post(
* path="/api/logout",
* summary="로그아웃 (Access 및 Token 무효화)",
* tags={"Auth"},
* security={{"ApiKeyAuth":{}}},
* @OA\Response(response=200, description="로그아웃 성공"),
* @OA\Response(response=401, description="인증 실패")
* )
*/
public function logout(Request $request)
{
$token = $request->header('X-API-KEY'); // 또는 Authorization 헤더
// 회원 테이블에서 해당 토큰으로 유저 찾기
$user = User::where('remember_token', $token)->first();
if ($user) {
$user->USER_TOKEN = null;
$user->save();
}
return response()->json(['message' => '로그아웃 완료']);
}
}

View File

@@ -0,0 +1,16 @@
<?php
namespace App\Http\Controllers\Api;
use App\Helpers\ApiResponse;
use Illuminate\Support\Facades\DB;
class CommonController
{
public static function getComeCode()
{
$query = DB::table('COM_CODE')
->select(['CODE_TP_ID', 'CODE_ID', 'CODE_VAL', 'CODE_DESC', 'USE_YN']);
return ApiResponse::response('get', $query);
}
}

View File

@@ -0,0 +1,43 @@
<?php
namespace App\Http\Controllers\Api;
use App\Http\Controllers\Controller;
use Illuminate\Http\Request;
use App\Services\FileService;
use App\Helpers\ApiResponse;
class FileController extends Controller
{
// 파일 업로드
public function upload(Request $request)
{
return ApiResponse::handle(function () use ($request) {
return FileService::uploadFiles($request->all());
}, '파일 업로드 성공', '파일 업로드 실패');
}
// 파일 목록 조회
public function list(Request $request)
{
return ApiResponse::handle(function () use ($request) {
return FileService::getFiles($request->all());
}, '파일 목록조회 성공', '파일 목록조회 실패');
}
// 파일 삭제
public function delete(Request $request)
{
return ApiResponse::handle(function () use ($request) {
return FileService::deleteFiles($request->all());
}, '파일 삭제 성공', '파일 삭제 실패');
}
// 파일 정보 조회 (단건)
public function findFile(Request $request)
{
return ApiResponse::handle(function () use ($request) {
return FileService::findFile($request->all());
}, '파일 정보 조회 성공', '파일 정보 조회 실패');
}
}

View File

@@ -0,0 +1,235 @@
<?php
namespace App\Http\Controllers\Api;
use Illuminate\Http\Request;
use App\Http\Controllers\Controller;
use App\Services\MemberService;
use App\Helpers\ApiResponse;
class MemberController extends Controller
{
/**
* @OA\Get(
* path="/api/member/index",
* summary="회원 목록 조회",
* description="회원 목록을 조회합니다.",
* tags={"Member"},
* security={{"ApiKeyAuth":{}}},
*
* @OA\Parameter(
* name="user_token",
* in="query",
* required=true,
* description="회원 인증용 토큰",
* @OA\Schema(type="string", example="abc123token")
* ),
* @OA\Parameter(
* name="type",
* in="query",
* required=false,
* description="조회 타입: 기본(default), 상세(info)",
* @OA\Schema(type="string", enum={"default", "info"}, example="default")
* ),
* @OA\Parameter(
* name="debug",
* in="query",
* required=false,
* description="디버그 모드 여부 (쿼리 로그 포함 여부)",
* @OA\Schema(type="boolean", example=true)
* ),
* @OA\Parameter(
* name="status",
* in="query",
* required=false,
* description="상태 필터링 (01,02,03 사용자만 조회)",
* @OA\Schema(type="boolean", example=true)
* ),
*
* @OA\Response(
* response=200,
* description="회원 목록 조회 성공",
* @OA\JsonContent(
* type="object",
* @OA\Property(property="success", type="boolean", example=true),
* @OA\Property(property="message", type="string", example="회원목록 조회 성공"),
* @OA\Property(
* property="data",
* type="object",
* @OA\Property(
* property="1",
* type="object",
* @OA\Property(property="mb_num", type="integer", example=1),
* @OA\Property(property="tn_num", type="string", example=null),
* @OA\Property(property="mb_id", type="string", example="admin"),
* @OA\Property(property="mb_name", type="string", example="권혁성"),
* @OA\Property(property="mb_phone", type="string", example="010-4820-9104"),
* @OA\Property(property="mb_mail", type="string", example="shine1324@gmail.com"),
* @OA\Property(property="email_verified_at", type="string", format="date-time", example=null),
* @OA\Property(property="mb_type", type="string", example=null),
* @OA\Property(property="mb_level", type="integer", example=1),
* @OA\Property(property="last_login", type="string", format="date-time", example=null),
* @OA\Property(property="reg_date", type="string", format="date-time", example="2025-07-16T09:28:41.000000Z"),
* @OA\Property(property="created_at", type="string", format="date-time", example=null),
* @OA\Property(property="updated_at", type="string", format="date-time", example="2025-07-16T09:30:56.000000Z")
* )
* ),
* @OA\Property(
* property="query",
* type="array",
* @OA\Items(type="string", example="select * from `members`")
* )
* )
* ),
*
* @OA\Response(response=401, description="인증 실패"),
* @OA\Response(response=403, description="권한 없음")
* )
*/
public function index(Request $request)
{
try {
$type = $request->input('type', 'default');
$userToken = $request->input('user_token', '');
$debug = $request->boolean('debug', false);
$result = MemberService::getMembers($userToken, $type, $debug);
return ApiResponse::success($result['data'], '회원목록 조회 성공',$result['query']);
} catch (\Throwable $e) {
return ApiResponse::error('회원목록 조회 실패', 500, [
'details' => $e->getMessage(),
]);
}
}
/**
* Show the form for creating a new resource.
*/
public function create()
{
//
}
/**
* Store a newly created resource in storage.
*/
public function store(Request $request)
{
return ApiResponse::handle(function () use ($request) {
return MemberService::setMember($request->all());
}, '회원등록 성공', '회원등록 실패');
}
/**
* @OA\Get (
* path="/api/member/show/{user_no}",
* summary="회원 상세조회",
* description="user_no 기준으로 회원 상세 정보를 조회합니다.",
* tags={"Member"},
* security={{"ApiKeyAuth":{}}},
*
* @OA\Parameter(
* name="user_no",
* in="path",
* required=true,
* description="회원 번호 (USER_NO)",
* @OA\Schema(type="integer", example=1)
* ),
* @OA\Parameter(
* name="debug",
* in="query",
* required=false,
* description="디버그 모드 여부 (쿼리 확인용)",
* @OA\Schema(type="boolean", example=true)
* ),
*
* @OA\Response(
* response=200,
* description="조회 성공",
* @OA\JsonContent(
* type="object",
* @OA\Property(property="success", type="boolean", example=true),
* @OA\Property(property="message", type="string", example="회원 상세조회 성공"),
* @OA\Property(
* property="data",
* type="object",
* @OA\Property(property="mb_num", type="integer", example=1),
* @OA\Property(property="tn_num", type="string", example=null),
* @OA\Property(property="mb_id", type="string", example="admin"),
* @OA\Property(property="mb_name", type="string", example="권혁성"),
* @OA\Property(property="mb_phone", type="string", example="010-4820-9104"),
* @OA\Property(property="mb_mail", type="string", example="shine1324@gmail.com"),
* @OA\Property(property="email_verified_at", type="string", format="date-time", example=null),
* @OA\Property(property="mb_type", type="string", example=null),
* @OA\Property(property="mb_level", type="integer", example=1),
* @OA\Property(property="last_login", type="string", format="date-time", example=null),
* @OA\Property(property="reg_date", type="string", format="date-time", example="2025-07-16T09:28:41.000000Z"),
* @OA\Property(property="created_at", type="string", format="date-time", example=null),
* @OA\Property(property="updated_at", type="string", format="date-time", example="2025-07-16T09:30:56.000000Z")
* ),
* @OA\Property(
* property="query",
* type="array",
* @OA\Items(type="string", example="select * from `members` where `mb_num` = 1 limit 1")
* )
* )
* ),
*
* @OA\Response(response=404, description="회원 정보 없음"),
* @OA\Response(response=401, description="인증 실패")
* )
*/
public function show(Request $request, $userNo)
{
try {
$debug = $request->boolean('debug', false);
$result = MemberService::getMember($userNo, $debug);
return ApiResponse::success($result['data'], '회원 상세조회 성공',$result['query']);
} catch (\Throwable $e) {
return ApiResponse::error('회원 상세조회 실패', 500, [
'details' => $e->getMessage(),
]);
}
}
/**
* Show the form for editing the specified resource.
*/
public function edit(string $id)
{
//
}
/**
* Update the specified resource in storage.
*/
public function update(Request $request, string $id)
{
//
}
/**
* Remove the specified resource from storage.
*/
public function delAdmin($userNo, Request $request)
{
return ApiResponse::handle(function () use ($userNo, $request) {
return MemberService::delAdmin($userNo);
}, '관리자 제외 성공', '관리자 제외 실패');
}
/**
* 관리자 설정
*/
public function setAdmin($userNo, Request $request)
{
return ApiResponse::handle(function () use ($userNo, $request) {
return MemberService::setAdmin($userNo);
}, '관리자 설정 성공', '관리자 설정 실패');
}
}

View File

@@ -0,0 +1,8 @@
<?php
namespace App\Http\Controllers;
abstract class Controller
{
//
}

28
app/Http/Kernel.php Normal file
View File

@@ -0,0 +1,28 @@
<?php
namespace App\Http;
use Illuminate\Foundation\Http\Kernel as HttpKernel;
class Kernel extends HttpKernel
{
/**
* 전역 미들웨어
*/
protected $middleware = [
\App\Http\Middleware\CorsMiddleware::class, // CORS 미들웨어 추가
];
/**
* 웹 미들웨어 그룹
*/
protected $middlewareGroups = [
'web' => [],
'api' => [],
];
/**
* 개별 미들웨어 설정
*/
protected $routeMiddleware = [];
}

View File

@@ -0,0 +1,50 @@
<?php
namespace App\Http\Middleware;
use Closure;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\DB;
use App\Models\User;
class ApiKeyMiddleware
{
public function handle(Request $request, Closure $next)
{
$apiKey = $request->header('X-API-KEY');
$validApiKey = false;
// 1. API 키가 유효한지 확인
if ($apiKey) {
$validApiKey = DB::table('api_keys')
->where('key', $apiKey)
->where('is_active', true)
->exists();
// 2. 회원 인증 (remember_token으로)
if (!$validApiKey) {
$user = User::where('remember_token', $apiKey)->first();
if ($user) {
$validApiKey = true;
// ✅ 세션에 유저 정보 저장
session(['Adm' => [
'idx' => $user->mb_num,
'id' => $user->mb_id,
'name' => $user->mb_name,
'level' => $user->mb_level,
'token' => $user->remember_token,
]]);
}
}
}
if (!$validApiKey) {
return response()->json(['message' => 'Unauthorized. Invalid or missing API key or token'], 401);
}
return $next($request);
}
}

View File

@@ -0,0 +1,27 @@
<?php
namespace App\Http\Middleware;
use Closure;
use Illuminate\Http\Request;
use App\Services\AdminPermissionService;
class CheckPermission
{
public function handle(Request $request, Closure $next, string $permissionCode)
{
$userToken = $request->input('user_token');
if (!$userToken) {
$userToken = $request->header('X-API-KEY');
if (!$userToken) {
return response()->json(['error' => '토큰이 없습니다.'], 401);
}
}
if (!AdminPermissionService::hasPermission($userToken, $permissionCode)) {
return response()->json(['error' => '권한이 없습니다.'], 403);
}
return $next($request);
}
}

View File

@@ -0,0 +1,34 @@
<?php
namespace App\Http\Middleware;
use Closure;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Session;
use App\Models\Member;
class CheckSwaggerAuth
{
public function handle(Request $request, Closure $next)
{
$token = Session::get('USER_TOKEN');
if (!$token) {
// 원래 URL 저장 후 로그인 페이지로 이동
Session::put('redirect_to', $request->fullUrl());
return redirect()->route('login');
}
$user = Member::where('remember_token', $token)->first();
if (!$user) {
Session::forget('USER_TOKEN');
Session::forget('USER_ID');
Session::put('redirect_to', $request->fullUrl());
return redirect()->route('login');
}
return $next($request);
}
}

View File

@@ -0,0 +1,25 @@
<?php
namespace App\Http\Middleware;
use Closure;
use Illuminate\Http\Request;
use Symfony\Component\HttpFoundation\Response;
class CorsMiddleware
{
public function handle(Request $request, Closure $next): Response
{
$response = $next($request);
$response->headers->set('Access-Control-Allow-Origin', '*');
$response->headers->set('Access-Control-Allow-Methods', 'GET, POST, PUT, DELETE, OPTIONS');
$response->headers->set('Access-Control-Allow-Headers', 'Content-Type, Authorization');
if ($request->isMethod('OPTIONS')) {
return response()->json([], 200, $response->headers->all());
}
return $response;
}
}

View File

@@ -0,0 +1,45 @@
<?php
namespace App\Http\Responses;
use Laravel\Fortify\Contracts\LoginResponse as LoginResponseContract;
use Illuminate\Support\Facades\Session;
use App\Models\User;
class CustomLoginResponse implements LoginResponseContract
{
public function toResponse($request)
{
$user = auth('web')->user();
if (!$user) {
abort(500, '로그인 유저 정보를 가져올 수 없습니다.');
}
//TOKEN 설정
$token = $user->remember_token;
if(!$token || substr($user->reg_date,0,10) < date('Y-m-d', strtotime('-15 day'))) {
$token = hash('sha256', $user->mb_id . now()->format('YmdHis'));
User::where('USER_NO', $user->mb_num)->update(['USER_TOKEN' => $token]);
}
// ✅ 세션에 유저 정보 저장
session(['Adm' => [
'idx' => $user->USER_NO,
'id' => $user->USER_ID,
'name' => $user->USER_NCNM,
'level' => $user->LEVEL,
'part' => $user->USER_PART,
'dept' => $user->USER_DEPT,
'token' => $token,
]]);
Session::put('USER_TOKEN', $token);
Session::put('USER_ID', $user->mb_id);
$redirectTo = session('redirect_to', route('dashboard'));
session()->forget('redirect_to');
return redirect()->to($redirectTo);
}
}

10
app/Models/ApiKey.php Normal file
View File

@@ -0,0 +1,10 @@
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
class ApiKey extends Model
{
protected $fillable = ['key', 'description', 'is_active'];
}

39
app/Models/Member.php Normal file
View File

@@ -0,0 +1,39 @@
<?php
namespace App\Models;
use Illuminate\Foundation\Auth\User as Authenticatable;
use Illuminate\Notifications\Notifiable;
use Laravel\Fortify\TwoFactorAuthenticatable;
use Laravel\Sanctum\HasApiTokens;
class Member extends Authenticatable
{
use HasApiTokens, Notifiable, TwoFactorAuthenticatable;
protected $primaryKey = 'mb_id'; // 기본 키 변경
protected $fillable = [
'mb_id', 'mb_pass', 'mb_name', 'mb_phone', 'mb_mail',
'email_verified_at', 'mb_type', 'mb_level', 'last_login',
'reg_date', 'remember_token'
];
protected $hidden = [
'mb_pass', 'remember_token',
];
protected $casts = [
'reg_date' => 'datetime',
];
public function getAuthPassword()
{
return $this->mb_pass; // 기본 비밀번호 필드를 mb_pass로 설정
}
public function getAuthIdentifierName()
{
return 'mb_id'; // 기본 로그인 필드를 mb_id로 변경
}
}

19
app/Models/SiteAdmin.php Normal file
View File

@@ -0,0 +1,19 @@
<?php
namespace App\Models;
use App\Traits\UppercaseAttributes;
use Illuminate\Database\Eloquent\Model;
class SiteAdmin extends Model
{
use UppercaseAttributes; // 테이블 컬럼명 대문자 처리
protected $table = 'SITE_ADMIN';
protected $primaryKey = 'UNO';
public $timestamps = false;
protected $fillable = [
'UNO', 'LEVEL'. 'COMMENT'
];
}

42
app/Models/User.php Normal file
View File

@@ -0,0 +1,42 @@
<?php
namespace App\Models;
use Illuminate\Foundation\Auth\User as Authenticatable;
use Illuminate\Notifications\Notifiable;
use Laravel\Fortify\TwoFactorAuthenticatable;
use Laravel\Sanctum\HasApiTokens;
use App\Traits\UppercaseAttributes;
class User extends Authenticatable
{
use HasApiTokens, Notifiable, TwoFactorAuthenticatable;
protected $table = 'members'; // 테이블 이름 변경
protected $primaryKey = 'mb_id'; // 기본 키 변경
protected $fillable = [
'mb_id', 'mb_pass', 'mb_name', 'mb_phone', 'mb_mail',
'email_verified_at', 'mb_type', 'mb_level', 'last_login',
'reg_date', 'remember_token'
];
protected $hidden = [
'mb_pass', 'remember_token',
];
protected $casts = [
'reg_date' => 'datetime',
];
public function getAuthPassword()
{
return $this->mb_pass; // 기본 비밀번호 필드를 mb_pass로 설정
}
public function getAuthIdentifierName()
{
return 'mb_id'; // 기본 로그인 필드를 mb_id로 변경
}
}

View File

@@ -0,0 +1,24 @@
<?php
namespace App\Providers;
use Illuminate\Support\ServiceProvider;
class AppServiceProvider extends ServiceProvider
{
/**
* Register any application services.
*/
public function register(): void
{
//
}
/**
* Bootstrap any application services.
*/
public function boot(): void
{
//
}
}

View File

@@ -0,0 +1,78 @@
<?php
namespace App\Providers;
use App\Actions\Fortify\CreateNewUser;
use App\Actions\Fortify\ResetUserPassword;
use App\Actions\Fortify\UpdateUserPassword;
use App\Actions\Fortify\UpdateUserProfileInformation;
use App\Models\Member;
use Illuminate\Cache\RateLimiting\Limit;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\RateLimiter;
use Illuminate\Support\ServiceProvider;
use Illuminate\Support\Str;
use Laravel\Fortify\Fortify;
use App\Models\User;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\Hash;
use Illuminate\Support\Facades\Log;
use Laravel\Fortify\Contracts\LoginResponse;
use App\Http\Responses\CustomLoginResponse;
class FortifyServiceProvider extends ServiceProvider
{
/**
* Register any application services.
*/
public function register(): void
{
// ✅ 커스텀 로그인 응답 등록
$this->app->singleton(LoginResponse::class, CustomLoginResponse::class);
}
/**
* Bootstrap any application services.
*/
public function boot(): void
{
Fortify::createUsersUsing(CreateNewUser::class);
Fortify::updateUserProfileInformationUsing(UpdateUserProfileInformation::class);
Fortify::updateUserPasswordsUsing(UpdateUserPassword::class);
Fortify::resetUserPasswordsUsing(ResetUserPassword::class);
// ✅ 로그인 시 `USER_ID`를 사용하도록 변경
Fortify::authenticateUsing(function (Request $request) {
$user = Member::where('mb_id', $request->USER_ID)->first();
if(!$user) return null;
// 기존 sha256 방식 확인
if ($user && strtoupper(hash('sha256', $request->password)) === $user->mb_pass) {
return $user;
}
// bcrypt 방식으로 저장된 사용자 로그인 처리
else if (Hash::check($request->password, $user->mb_pass)) {
return $user;
}
return null;
});
Fortify::loginView(fn() => view('auth.login')); // 로그인 페이지 지정
RateLimiter::for('login', function (Request $request) {
$throttleKey = Str::transliterate(Str::lower($request->input('USER_ID')).'|'.$request->ip());
return Limit::perMinute(5)->by($throttleKey);
});
RateLimiter::for('two-factor', function (Request $request) {
return Limit::perMinute(5)->by($request->session()->get('login.id'));
});
}
}

View File

@@ -0,0 +1,43 @@
<?php
namespace App\Providers;
use App\Actions\Jetstream\DeleteUser;
use Illuminate\Support\ServiceProvider;
use Laravel\Jetstream\Jetstream;
class JetstreamServiceProvider extends ServiceProvider
{
/**
* Register any application services.
*/
public function register(): void
{
//
}
/**
* Bootstrap any application services.
*/
public function boot(): void
{
$this->configurePermissions();
Jetstream::deleteUsersUsing(DeleteUser::class);
}
/**
* Configure the permissions that are available within the application.
*/
protected function configurePermissions(): void
{
Jetstream::defaultApiTokenPermissions(['read']);
Jetstream::permissions([
'create',
'read',
'update',
'delete',
]);
}
}

View File

@@ -0,0 +1,38 @@
<?php
namespace App\Services;
use Illuminate\Support\Facades\DB;
use App\Models\User;
use App\Models\SiteAdmin;
class AdminPermissionService
{
public static function getPermissionsByToken(string $userToken): array
{
$user = User::where('USER_TOKEN', $userToken)
->first();
if (!$user) return [];
$admin = SiteAdmin::where('UNO', $user->USER_NO)
->first();
if (!$admin) return [];
$permissionCodes = DB::table('SITE_ADMIN_USER_ROLE AS ur')
->join('SITE_ADMIN_ROLE_PERMISSION AS rp', 'ur.ROLE_ID', '=', 'rp.ROLE_ID')
->join('SITE_ADMIN_PERMISSIONS AS p', 'rp.PERMISSION_ID', '=', 'p.ID')
->where('ur.USER_ID', $admin->A_IDX)
->pluck('p.CODE')
->toArray();
return $permissionCodes;
}
public static function hasPermission(string $userToken, string $code): bool
{
$permissions = self::getPermissionsByToken($userToken);
return in_array($code, $permissions);
}
}

View File

@@ -0,0 +1,188 @@
<?php
namespace App\Services;
use App\Helpers\ApiResponse;
use Illuminate\Support\Facades\DB;
class FileService
{
public static function saveFiles($files, string $table, string $t_id, string $t_id_type = '00')
{
if (isset($files) && is_array($files)) {
foreach ($files as $file) {
$fileName = $file->getClientOriginalName();
$randomName = bin2hex(random_bytes(16));
$fileType = $file->getClientMimeType();
$fileSize = $file->getSize();
//$tempFile = $file->getPathname();
$folder = config('custom.data_path') . substr($t_id, 0, 6) . "/";
$targetPath = $folder . $randomName;
if (!is_dir($folder)) {
mkdir($folder, 0755, true);
}
try {
//move_uploaded_file($tempFile, $targetPath);
$file->move($folder, $randomName);
chmod($targetPath, 0644);
DB::table('SITE_FILES')->insert([
'F_NAME' => $fileName,
'R_NAME' => $randomName,
'TABLE' => $table,
'T_ID' => $t_id,
'T_ID_TYPE' => $t_id_type,
'F_TYPE' => $fileType,
'F_SIZE' => $fileSize,
'REG_USER_NO' => session('Adm.idx') ?? 1,
]);
} catch (\Exception $e) {
return ApiResponse::error('파일업로드 실패', 422);
}
}
}
}
public static function uploadFiles($request)
{
$files = $request['upload'] ?? '';
$table = $request['table'] ?? 'COMPANY_INFO';
$t_id = $request['com_no'];
$file_no = $request['file_no'] ?? '';
if (isset($files) && is_array($files)) {
foreach ($files as $key => $file) {
$originalName = $file->getClientOriginalName(); // 예: "파일명.jpg"
$ext = pathinfo($originalName, PATHINFO_EXTENSION); // 확장자만 추출: "jpg"
$userInputName = $request['fileName'][$key] ?? null;
$fileName = $userInputName ? $userInputName . '.' . $ext : $originalName;
$randomName = bin2hex(random_bytes(16));
$fileType = $file->getClientMimeType();
$fileSize = $file->getSize();
$t_id_type = $request['fileType'][$key] ?? '00';
$folder = config('custom.data_path') . substr($t_id, 0, 6) . "/";
$targetPath = $folder . $randomName;
if (!is_dir($folder)) {
mkdir($folder, 0755, true);
}
try {
$file->move($folder, $randomName);
chmod($targetPath, 0644);
if (!empty($file_no)) {
self::deleteFiles(['f_id' => $file_no]);
}
// 신규 파일 등록
DB::table('SITE_FILES')->insert([
'F_NAME' => $fileName,
'R_NAME' => $randomName,
'TABLE' => $table,
'T_ID' => $t_id,
'T_ID_TYPE' => $t_id_type,
'F_TYPE' => $fileType,
'F_SIZE' => $fileSize,
'REG_USER_NO' => session('Adm.idx') ?? 1,
]);
} catch (\Exception $e) {
return ApiResponse::error('파일업로드 실패', 422);
}
}
}else if($file_no) {
// 기존파일인데 업로드 파일이 없을경우 이름과 타입만 변경
if ($request['fileName'][1]) {
$ext = pathinfo(DB::table('SITE_FILES')->where('F_NO', $file_no)->value('F_NAME'), PATHINFO_EXTENSION);
$data['F_NAME'] = $request['fileName'][1] . '.' . $ext;
}
if ($request['fileType'][1]) {
$data['T_ID_TYPE'] = $request['fileType'][1];
}
DB::table('SITE_FILES')->where('F_NO', $file_no)->update($data);
}
return self::getFiles($request);
}
public static function getFiles(array $params): array
{
$tType = $params['t_type'] ?? null;
$table = $params['table'] ?? '';
$idx = $params['idx'] ?? '';
$com_no = $params['com_no'] ?? '';
$params['debug'] = $params['debug'] ?? true;
$query = DB::table('SITE_FILES as SF')
->select('SF.T_ID', 'SF.F_NO', 'SF.F_NAME', 'SF.R_NAME', DB::raw('LEFT(SF.T_ID, 6) as PATH'), 'SF.REG_USER_NO');
if ($table) {
$query->where('SF.TABLE', $table);
}
if ($idx) {
$query->whereIn('SF.T_ID', explode(',', $idx));
}else if ($com_no) {
$query->where('SF.T_ID', $com_no);
}
if ($tType) {
$query->where('SF.T_ID_TYPE', $tType);
}
return ApiResponse::response('getSub', $query, $params['debug'], 'T_ID');
}
public static function deleteFiles(array $params): string
{
$table = $params['TABLE'] ?? null;
$t_id = $params['T_ID'] ?? null;
$f_id = $params['f_id'] ?? null;
$query = DB::table('SITE_FILES');
if ($table && $t_id) {
$query->where('TABLE', $table)->where('T_ID', $t_id);
} else if ($f_id) {
$query->whereIn('F_NO', explode(',', $f_id));
} else {
return 'Error';
logger('파일삭제 - 검색조건이 없음');
}
$files = $query->get();
if (empty($files)) {
return 'Success';
}
foreach ($files as $file) {
$filePath = config('custom.data_path') . substr($file->T_ID, 0, 6) . "/" . $file->R_NAME;
if (file_exists($filePath)) {
unlink($filePath);
}
}
$query->delete();
return 'Success';
}
public static function findFile(array $params): ?array
{
$fileName = $params['fileName'] ?? '';
$F_NO = $params['file_no'] ?? '';
$query = DB::table('SITE_FILES as SF')
->select('F_NAME', 'T_ID', 'F_TYPE', DB::raw("IFNULL((SELECT COM_NAME FROM COMPANY_INFO CI WHERE SF.T_ID = CI.COM_NO AND SF.TABLE = 'COMPANY_INFO' LIMIT 1), '') as COM_NAME"));
if($F_NO) $query->where('F_NO', $F_NO);
else $query->where('R_NAME', $fileName);
return ApiResponse::response('first', $query, $params['debug']);
}
}

View File

@@ -0,0 +1,151 @@
<?php
namespace App\Services;
use App\Helpers\ApiResponse;
use App\Models\Member;
use Illuminate\Support\Facades\DB;
class MemberService
{
/**
* 회원 조회(리스트)
*/
public static function getMembers(string $userToken, string $type = 'default', bool $debug = false, bool $status = false)
{
$query = new Member();
return ApiResponse::response('get', $query, $debug, 'mb_num');
}
/**
* 단일 회원 조회
*/
public static function getMember(int $userNo, bool $debug = false)
{
$query = Member::where('mb_num', $userNo);
return ApiResponse::response('first', $query, $debug);
}
/**
* 회원 등록 또는 수정
*/
public static function setMember(array $params)
{
if ($res = ApiResponse::validate(isset($params['user_id']), '아이디 없음')) return $res;
if ($res = ApiResponse::validate(isset($params['user_ncnm']), '이름 없음')) return $res;
$pwd1 = $params['user_pwd1'] ?? null;
$pwd2 = $params['user_pwd2'] ?? null;
if ($res = ApiResponse::validate(
!$pwd1 || $pwd1 === $pwd2,
'비밀번호가 일치하지 않음'
)) return $res;
$now = now();
$data = [
'USER_EMAIL' => $params['user_email'] ?? null,
'USER_HP' => $params['user_hp'] ?? null,
'USER_IP' => $params['user_ip'] ?? null,
'ALT_DTTM' => $now,
];
if (!empty($params['user_start_dt'])) {
$data['USER_START_DT'] = $params['user_start_dt'];
}
if (!empty($params['user_end_dt'])) {
$data['USER_END_DT'] = $params['user_end_dt'];
}
// 신규 등록
if (empty($params['user_no'])) {
// 초기 비빌번호 설정이 없으면 0000 으로 셋팅
$pwd = $pwd1 ?? '0000';
$data += [
'USER_ID' => $params['user_id'],
'USER_PWD' => hash('sha256', $pwd),
'USER_NCNM' => $params['user_ncnm'] ?? null,
'USER_PART' => $params['user_part'] ?? null,
'USER_DEPT' => $params['user_dept'] ?? null,
'USER_ROLE' => $params['user_role'] ?? null,
'USER_STATUS' => $params['user_status'] ?? null,
'USER_MEMO' => $params['user_memo'] ?? null,
'REG_DTTM' => $now,
'ALT_DTTM' => $now,
];
DB::table('SITE_USER_INFO')->insert($data);
}
// 수정
else {
if (!empty($pwd1)) {
$data['USER_PWD'] = hash('sha256', $pwd1);
}
if (AdminPermissionService::hasPermission(session('Adm.token'), 'AC')) {
$data += [
'USER_ID' => $params['user_id'],
'USER_NCNM' => $params['user_ncnm'],
'USER_PART' => $params['user_part'],
'USER_DEPT' => $params['user_dept'],
'USER_ROLE' => $params['user_role'],
'USER_STATUS' => $params['user_status'],
'USER_MEMO' => $params['user_memo'],
'ALT_DTTM' => $now,
];
}
DB::table('SITE_USER_INFO')
->where('USER_NO', $params['user_no'])
->update($data);
}
return ApiResponse::response('success');
}
/**
* 관리자 권한 삭제
*/
public static function delAdmin(int $userNo)
{
DB::table('SITE_ADMIN')->where('UNO', $userNo)->delete();
DB::table('SITE_USER_INFO')
->where('USER_NO', $userNo)
->update(['USER_STATUS' => '02']);
return ApiResponse::response('success');
}
/**
* 관리자 권한 등록
*/
public static function setAdmin(int $userNo)
{
$mem = DB::table('SITE_USER_INFO')
->select('USER_ROLE', 'USER_PART')
->where('USER_NO', $userNo)
->first();
if (!$mem) {
return ApiResponse::error('존재하지 않는 회원입니다.', 404);
}
DB::table('SITE_ADMIN')->updateOrInsert(
['UNO' => $userNo],
['LEVEL' => 'public', 'COMMENT' => '일반관리자']
);
DB::table('SITE_USER_INFO')
->where('USER_NO', $userNo)
->update(['USER_STATUS' => '01']);
return ApiResponse::response('success');
}
}

View File

@@ -0,0 +1,24 @@
<?php
namespace App\Traits;
trait UppercaseAttributes
{
protected function getAttributeFromArray($key)
{
$upperKey = strtoupper($key);
return parent::getAttributeFromArray($upperKey);
}
public function __get($key)
{
$upperKey = strtoupper($key);
return parent::__get($upperKey);
}
public function __set($key, $value)
{
$upperKey = strtoupper($key);
return parent::__set($upperKey, $value);
}
}

View File

@@ -0,0 +1,17 @@
<?php
namespace App\View\Components;
use Illuminate\View\Component;
use Illuminate\View\View;
class AppLayout extends Component
{
/**
* Get the view / contents that represents the component.
*/
public function render(): View
{
return view('layouts.app');
}
}

View File

@@ -0,0 +1,17 @@
<?php
namespace App\View\Components;
use Illuminate\View\Component;
use Illuminate\View\View;
class GuestLayout extends Component
{
/**
* Get the view / contents that represents the component.
*/
public function render(): View
{
return view('layouts.guest');
}
}

18
artisan Executable file
View File

@@ -0,0 +1,18 @@
#!/usr/bin/env php
<?php
use Illuminate\Foundation\Application;
use Symfony\Component\Console\Input\ArgvInput;
define('LARAVEL_START', microtime(true));
// Register the Composer autoloader...
require __DIR__.'/vendor/autoload.php';
// Bootstrap Laravel and handle the command...
/** @var Application $app */
$app = require_once __DIR__.'/bootstrap/app.php';
$status = $app->handleCommand(new ArgvInput);
exit($status);

33
bootstrap/app.php Normal file
View File

@@ -0,0 +1,33 @@
<?php
use Illuminate\Foundation\Application;
use Illuminate\Foundation\Configuration\Exceptions;
use Illuminate\Foundation\Configuration\Middleware;
use App\Http\Middleware\CorsMiddleware;
use App\Http\Middleware\ApiKeyMiddleware;
use App\Http\Middleware\CheckSwaggerAuth;
use App\Http\Middleware\CheckPermission;
return Application::configure(basePath: dirname(__DIR__))
->withRouting(
web: __DIR__.'/../routes/web.php',
api: __DIR__.'/../routes/api.php',
commands: __DIR__.'/../routes/console.php',
health: '/up',
)
->withMiddleware(function (Middleware $middleware) {
// CORS 미들웨어 추가
$middleware->append(CorsMiddleware::class);
$middleware->alias([
'auth.apikey' => ApiKeyMiddleware::class, // Api Key 인증 미들웨어
'swagger.auth' => CheckSwaggerAuth::class, // Swagger 인증 미들웨어
'permission' => CheckPermission::class, // 권한확인 미들웨어
]);
})
->withExceptions(function (Exceptions $exceptions) {
//
})->create();

7
bootstrap/providers.php Normal file
View File

@@ -0,0 +1,7 @@
<?php
return [
App\Providers\AppServiceProvider::class,
App\Providers\FortifyServiceProvider::class,
App\Providers\JetstreamServiceProvider::class,
];

75
composer.json Normal file
View File

@@ -0,0 +1,75 @@
{
"$schema": "https://getcomposer.org/schema.json",
"name": "laravel/laravel",
"type": "project",
"description": "The skeleton application for the Laravel framework.",
"keywords": ["laravel", "framework"],
"license": "MIT",
"require": {
"php": "^8.2",
"darkaonline/l5-swagger": "^9.0",
"laravel/framework": "^12.0",
"laravel/jetstream": "^5.3",
"laravel/sanctum": "^4.0",
"laravel/tinker": "^2.10.1",
"livewire/livewire": "^3.0"
},
"require-dev": {
"fakerphp/faker": "^1.23",
"laravel/pail": "^1.2.2",
"laravel/pint": "^1.13",
"laravel/sail": "^1.41",
"mockery/mockery": "^1.6",
"nunomaduro/collision": "^8.6",
"phpunit/phpunit": "^11.5.3"
},
"autoload": {
"psr-4": {
"App\\": "app/",
"Database\\Factories\\": "database/factories/",
"Database\\Seeders\\": "database/seeders/"
}
},
"autoload-dev": {
"psr-4": {
"Tests\\": "tests/"
}
},
"scripts": {
"post-autoload-dump": [
"Illuminate\\Foundation\\ComposerScripts::postAutoloadDump",
"@php artisan package:discover --ansi"
],
"post-update-cmd": [
"@php artisan vendor:publish --tag=laravel-assets --ansi --force"
],
"post-root-package-install": [
"@php -r \"file_exists('.env') || copy('.env.example', '.env');\""
],
"post-create-project-cmd": [
"@php artisan key:generate --ansi",
"@php -r \"file_exists('database/database.sqlite') || touch('database/database.sqlite');\"",
"@php artisan migrate --graceful --ansi"
],
"dev": [
"Composer\\Config::disableProcessTimeout",
"npx concurrently -c \"#93c5fd,#c4b5fd,#fb7185,#fdba74\" \"php artisan serve\" \"php artisan queue:listen --tries=1\" \"php artisan pail --timeout=0\" \"npm run dev\" --names=server,queue,logs,vite"
]
},
"extra": {
"laravel": {
"dont-discover": []
}
},
"config": {
"optimize-autoloader": true,
"preferred-install": "dist",
"sort-packages": true,
"allow-plugins": {
"pestphp/pest-plugin": true,
"php-http/discovery": true
}
},
"minimum-stability": "stable",
"prefer-stable": true
}

126
config/app.php Normal file
View File

@@ -0,0 +1,126 @@
<?php
return [
/*
|--------------------------------------------------------------------------
| Application Name
|--------------------------------------------------------------------------
|
| This value is the name of your application, which will be used when the
| framework needs to place the application's name in a notification or
| other UI elements where an application name needs to be displayed.
|
*/
'name' => env('APP_NAME', 'Laravel'),
/*
|--------------------------------------------------------------------------
| Application Environment
|--------------------------------------------------------------------------
|
| This value determines the "environment" your application is currently
| running in. This may determine how you prefer to configure various
| services the application utilizes. Set this in your ".env" file.
|
*/
'env' => env('APP_ENV', 'production'),
/*
|--------------------------------------------------------------------------
| Application Debug Mode
|--------------------------------------------------------------------------
|
| When your application is in debug mode, detailed error messages with
| stack traces will be shown on every error that occurs within your
| application. If disabled, a simple generic error page is shown.
|
*/
'debug' => (bool) env('APP_DEBUG', false),
/*
|--------------------------------------------------------------------------
| Application URL
|--------------------------------------------------------------------------
|
| This URL is used by the console to properly generate URLs when using
| the Artisan command line tool. You should set this to the root of
| the application so that it's available within Artisan commands.
|
*/
'url' => env('APP_URL', 'http://localhost'),
/*
|--------------------------------------------------------------------------
| Application Timezone
|--------------------------------------------------------------------------
|
| Here you may specify the default timezone for your application, which
| will be used by the PHP date and date-time functions. The timezone
| is set to "UTC" by default as it is suitable for most use cases.
|
*/
'timezone' => 'Asia/Seoul',
/*
|--------------------------------------------------------------------------
| Application Locale Configuration
|--------------------------------------------------------------------------
|
| The application locale determines the default locale that will be used
| by Laravel's translation / localization methods. This option can be
| set to any locale for which you plan to have translation strings.
|
*/
'locale' => env('APP_LOCALE', 'en'),
'fallback_locale' => env('APP_FALLBACK_LOCALE', 'en'),
'faker_locale' => env('APP_FAKER_LOCALE', 'en_US'),
/*
|--------------------------------------------------------------------------
| Encryption Key
|--------------------------------------------------------------------------
|
| This key is utilized by Laravel's encryption services and should be set
| to a random, 32 character string to ensure that all encrypted values
| are secure. You should do this prior to deploying the application.
|
*/
'cipher' => 'AES-256-CBC',
'key' => env('APP_KEY'),
'previous_keys' => [
...array_filter(
explode(',', env('APP_PREVIOUS_KEYS', ''))
),
],
/*
|--------------------------------------------------------------------------
| Maintenance Mode Driver
|--------------------------------------------------------------------------
|
| These configuration options determine the driver used to determine and
| manage Laravel's "maintenance mode" status. The "cache" driver will
| allow maintenance mode to be controlled across multiple machines.
|
| Supported drivers: "file", "cache"
|
*/
'maintenance' => [
'driver' => env('APP_MAINTENANCE_DRIVER', 'file'),
'store' => env('APP_MAINTENANCE_STORE', 'database'),
],
];

115
config/auth.php Normal file
View File

@@ -0,0 +1,115 @@
<?php
return [
/*
|--------------------------------------------------------------------------
| Authentication Defaults
|--------------------------------------------------------------------------
|
| This option defines the default authentication "guard" and password
| reset "broker" for your application. You may change these values
| as required, but they're a perfect start for most applications.
|
*/
'defaults' => [
'guard' => env('AUTH_GUARD', 'web'),
'passwords' => env('AUTH_PASSWORD_BROKER', 'users'),
],
/*
|--------------------------------------------------------------------------
| Authentication Guards
|--------------------------------------------------------------------------
|
| Next, you may define every authentication guard for your application.
| Of course, a great default configuration has been defined for you
| which utilizes session storage plus the Eloquent user provider.
|
| All authentication guards have a user provider, which defines how the
| users are actually retrieved out of your database or other storage
| system used by the application. Typically, Eloquent is utilized.
|
| Supported: "session"
|
*/
'guards' => [
'web' => [
'driver' => 'session',
'provider' => 'users',
],
],
/*
|--------------------------------------------------------------------------
| User Providers
|--------------------------------------------------------------------------
|
| All authentication guards have a user provider, which defines how the
| users are actually retrieved out of your database or other storage
| system used by the application. Typically, Eloquent is utilized.
|
| If you have multiple user tables or models you may configure multiple
| providers to represent the model / table. These providers may then
| be assigned to any extra authentication guards you have defined.
|
| Supported: "database", "eloquent"
|
*/
'providers' => [
'users' => [
'driver' => 'eloquent',
'model' => env('AUTH_MODEL', App\Models\User::class),
],
// 'users' => [
// 'driver' => 'database',
// 'table' => 'users',
// ],
],
/*
|--------------------------------------------------------------------------
| Resetting Passwords
|--------------------------------------------------------------------------
|
| These configuration options specify the behavior of Laravel's password
| reset functionality, including the table utilized for token storage
| and the user provider that is invoked to actually retrieve users.
|
| The expiry time is the number of minutes that each reset token will be
| considered valid. This security feature keeps tokens short-lived so
| they have less time to be guessed. You may change this as needed.
|
| The throttle setting is the number of seconds a user must wait before
| generating more password reset tokens. This prevents the user from
| quickly generating a very large amount of password reset tokens.
|
*/
'passwords' => [
'users' => [
'provider' => 'users',
'table' => env('AUTH_PASSWORD_RESET_TOKEN_TABLE', 'password_reset_tokens'),
'expire' => 60,
'throttle' => 60,
],
],
/*
|--------------------------------------------------------------------------
| Password Confirmation Timeout
|--------------------------------------------------------------------------
|
| Here you may define the amount of seconds before a password confirmation
| window expires and users are asked to re-enter their password via the
| confirmation screen. By default, the timeout lasts for three hours.
|
*/
'password_timeout' => env('AUTH_PASSWORD_TIMEOUT', 10800),
];

108
config/cache.php Normal file
View File

@@ -0,0 +1,108 @@
<?php
use Illuminate\Support\Str;
return [
/*
|--------------------------------------------------------------------------
| Default Cache Store
|--------------------------------------------------------------------------
|
| This option controls the default cache store that will be used by the
| framework. This connection is utilized if another isn't explicitly
| specified when running a cache operation inside the application.
|
*/
'default' => env('CACHE_STORE', 'database'),
/*
|--------------------------------------------------------------------------
| Cache Stores
|--------------------------------------------------------------------------
|
| Here you may define all of the cache "stores" for your application as
| well as their drivers. You may even define multiple stores for the
| same cache driver to group types of items stored in your caches.
|
| Supported drivers: "array", "database", "file", "memcached",
| "redis", "dynamodb", "octane", "null"
|
*/
'stores' => [
'array' => [
'driver' => 'array',
'serialize' => false,
],
'database' => [
'driver' => 'database',
'connection' => env('DB_CACHE_CONNECTION'),
'table' => env('DB_CACHE_TABLE', 'cache'),
'lock_connection' => env('DB_CACHE_LOCK_CONNECTION'),
'lock_table' => env('DB_CACHE_LOCK_TABLE'),
],
'file' => [
'driver' => 'file',
'path' => storage_path('framework/cache/data'),
'lock_path' => storage_path('framework/cache/data'),
],
'memcached' => [
'driver' => 'memcached',
'persistent_id' => env('MEMCACHED_PERSISTENT_ID'),
'sasl' => [
env('MEMCACHED_USERNAME'),
env('MEMCACHED_PASSWORD'),
],
'options' => [
// Memcached::OPT_CONNECT_TIMEOUT => 2000,
],
'servers' => [
[
'host' => env('MEMCACHED_HOST', '127.0.0.1'),
'port' => env('MEMCACHED_PORT', 11211),
'weight' => 100,
],
],
],
'redis' => [
'driver' => 'redis',
'connection' => env('REDIS_CACHE_CONNECTION', 'cache'),
'lock_connection' => env('REDIS_CACHE_LOCK_CONNECTION', 'default'),
],
'dynamodb' => [
'driver' => 'dynamodb',
'key' => env('AWS_ACCESS_KEY_ID'),
'secret' => env('AWS_SECRET_ACCESS_KEY'),
'region' => env('AWS_DEFAULT_REGION', 'us-east-1'),
'table' => env('DYNAMODB_CACHE_TABLE', 'cache'),
'endpoint' => env('DYNAMODB_ENDPOINT'),
],
'octane' => [
'driver' => 'octane',
],
],
/*
|--------------------------------------------------------------------------
| Cache Key Prefix
|--------------------------------------------------------------------------
|
| When utilizing the APC, database, memcached, Redis, and DynamoDB cache
| stores, there might be other applications using the same cache. For
| that reason, you may prefix every cache key to avoid collisions.
|
*/
'prefix' => env('CACHE_PREFIX', Str::slug(env('APP_NAME', 'laravel'), '_').'_cache_'),
];

12
config/cors.php Normal file
View File

@@ -0,0 +1,12 @@
<?php
return [
'paths' => ['api/*'], // CORS를 적용할 경로
'allowed_methods' => ['*'], // 모든 HTTP 메서드 허용
'allowed_origins' => ['*'], // 모든 도메인 허용 (보안 주의)
'allowed_origins_patterns' => [],
'allowed_headers' => ['*'], // 모든 헤더 허용
'exposed_headers' => [],
'max_age' => 0,
'supports_credentials' => false,
];

7
config/custom.php Normal file
View File

@@ -0,0 +1,7 @@
<?php
return [
'dir_permission' => env('DIR_PERMISSION', 0755),
'file_permission' => env('FILE_PERMISSION', 0644),
'data_path' => env('DATA_PATH', '/home/webservice/HamAdmin/data/uploads/'),
];

174
config/database.php Normal file
View File

@@ -0,0 +1,174 @@
<?php
use Illuminate\Support\Str;
return [
/*
|--------------------------------------------------------------------------
| Default Database Connection Name
|--------------------------------------------------------------------------
|
| Here you may specify which of the database connections below you wish
| to use as your default connection for database operations. This is
| the connection which will be utilized unless another connection
| is explicitly specified when you execute a query / statement.
|
*/
'default' => env('DB_CONNECTION', 'sqlite'),
/*
|--------------------------------------------------------------------------
| Database Connections
|--------------------------------------------------------------------------
|
| Below are all of the database connections defined for your application.
| An example configuration is provided for each database system which
| is supported by Laravel. You're free to add / remove connections.
|
*/
'connections' => [
'sqlite' => [
'driver' => 'sqlite',
'url' => env('DB_URL'),
'database' => env('DB_DATABASE', database_path('database.sqlite')),
'prefix' => '',
'foreign_key_constraints' => env('DB_FOREIGN_KEYS', true),
'busy_timeout' => null,
'journal_mode' => null,
'synchronous' => null,
],
'mysql' => [
'driver' => 'mysql',
'url' => env('DB_URL'),
'host' => env('DB_HOST', '127.0.0.1'),
'port' => env('DB_PORT', '3306'),
'database' => env('DB_DATABASE', 'laravel'),
'username' => env('DB_USERNAME', 'root'),
'password' => env('DB_PASSWORD', ''),
'unix_socket' => env('DB_SOCKET', ''),
'charset' => env('DB_CHARSET', 'utf8mb4'),
'collation' => env('DB_COLLATION', 'utf8mb4_unicode_ci'),
'prefix' => '',
'prefix_indexes' => true,
'strict' => true,
'engine' => null,
'options' => extension_loaded('pdo_mysql') ? array_filter([
PDO::MYSQL_ATTR_SSL_CA => env('MYSQL_ATTR_SSL_CA'),
]) : [],
],
'mariadb' => [
'driver' => 'mariadb',
'url' => env('DB_URL'),
'host' => env('DB_HOST', '127.0.0.1'),
'port' => env('DB_PORT', '3306'),
'database' => env('DB_DATABASE', 'laravel'),
'username' => env('DB_USERNAME', 'root'),
'password' => env('DB_PASSWORD', ''),
'unix_socket' => env('DB_SOCKET', ''),
'charset' => env('DB_CHARSET', 'utf8mb4'),
'collation' => env('DB_COLLATION', 'utf8mb4_unicode_ci'),
'prefix' => '',
'prefix_indexes' => true,
'strict' => true,
'engine' => null,
'options' => extension_loaded('pdo_mysql') ? array_filter([
PDO::MYSQL_ATTR_SSL_CA => env('MYSQL_ATTR_SSL_CA'),
]) : [],
],
'pgsql' => [
'driver' => 'pgsql',
'url' => env('DB_URL'),
'host' => env('DB_HOST', '127.0.0.1'),
'port' => env('DB_PORT', '5432'),
'database' => env('DB_DATABASE', 'laravel'),
'username' => env('DB_USERNAME', 'root'),
'password' => env('DB_PASSWORD', ''),
'charset' => env('DB_CHARSET', 'utf8'),
'prefix' => '',
'prefix_indexes' => true,
'search_path' => 'public',
'sslmode' => 'prefer',
],
'sqlsrv' => [
'driver' => 'sqlsrv',
'url' => env('DB_URL'),
'host' => env('DB_HOST', 'localhost'),
'port' => env('DB_PORT', '1433'),
'database' => env('DB_DATABASE', 'laravel'),
'username' => env('DB_USERNAME', 'root'),
'password' => env('DB_PASSWORD', ''),
'charset' => env('DB_CHARSET', 'utf8'),
'prefix' => '',
'prefix_indexes' => true,
// 'encrypt' => env('DB_ENCRYPT', 'yes'),
// 'trust_server_certificate' => env('DB_TRUST_SERVER_CERTIFICATE', 'false'),
],
],
/*
|--------------------------------------------------------------------------
| Migration Repository Table
|--------------------------------------------------------------------------
|
| This table keeps track of all the migrations that have already run for
| your application. Using this information, we can determine which of
| the migrations on disk haven't actually been run on the database.
|
*/
'migrations' => [
'table' => 'migrations',
'update_date_on_publish' => true,
],
/*
|--------------------------------------------------------------------------
| Redis Databases
|--------------------------------------------------------------------------
|
| Redis is an open source, fast, and advanced key-value store that also
| provides a richer body of commands than a typical key-value system
| such as Memcached. You may define your connection settings here.
|
*/
'redis' => [
'client' => env('REDIS_CLIENT', 'phpredis'),
'options' => [
'cluster' => env('REDIS_CLUSTER', 'redis'),
'prefix' => env('REDIS_PREFIX', Str::slug(env('APP_NAME', 'laravel'), '_').'_database_'),
'persistent' => env('REDIS_PERSISTENT', false),
],
'default' => [
'url' => env('REDIS_URL'),
'host' => env('REDIS_HOST', '127.0.0.1'),
'username' => env('REDIS_USERNAME'),
'password' => env('REDIS_PASSWORD'),
'port' => env('REDIS_PORT', '6379'),
'database' => env('REDIS_DB', '0'),
],
'cache' => [
'url' => env('REDIS_URL'),
'host' => env('REDIS_HOST', '127.0.0.1'),
'username' => env('REDIS_USERNAME'),
'password' => env('REDIS_PASSWORD'),
'port' => env('REDIS_PORT', '6379'),
'database' => env('REDIS_CACHE_DB', '1'),
],
],
];

80
config/filesystems.php Normal file
View File

@@ -0,0 +1,80 @@
<?php
return [
/*
|--------------------------------------------------------------------------
| Default Filesystem Disk
|--------------------------------------------------------------------------
|
| Here you may specify the default filesystem disk that should be used
| by the framework. The "local" disk, as well as a variety of cloud
| based disks are available to your application for file storage.
|
*/
'default' => env('FILESYSTEM_DISK', 'local'),
/*
|--------------------------------------------------------------------------
| Filesystem Disks
|--------------------------------------------------------------------------
|
| Below you may configure as many filesystem disks as necessary, and you
| may even configure multiple disks for the same driver. Examples for
| most supported storage drivers are configured here for reference.
|
| Supported drivers: "local", "ftp", "sftp", "s3"
|
*/
'disks' => [
'local' => [
'driver' => 'local',
'root' => storage_path('app/private'),
'serve' => true,
'throw' => false,
'report' => false,
],
'public' => [
'driver' => 'local',
'root' => storage_path('app/public'),
'url' => env('APP_URL').'/storage',
'visibility' => 'public',
'throw' => false,
'report' => false,
],
's3' => [
'driver' => 's3',
'key' => env('AWS_ACCESS_KEY_ID'),
'secret' => env('AWS_SECRET_ACCESS_KEY'),
'region' => env('AWS_DEFAULT_REGION'),
'bucket' => env('AWS_BUCKET'),
'url' => env('AWS_URL'),
'endpoint' => env('AWS_ENDPOINT'),
'use_path_style_endpoint' => env('AWS_USE_PATH_STYLE_ENDPOINT', false),
'throw' => false,
'report' => false,
],
],
/*
|--------------------------------------------------------------------------
| Symbolic Links
|--------------------------------------------------------------------------
|
| Here you may configure the symbolic links that will be created when the
| `storage:link` Artisan command is executed. The array keys should be
| the locations of the links and the values should be their targets.
|
*/
'links' => [
public_path('storage') => storage_path('app/public'),
],
];

160
config/fortify.php Normal file
View File

@@ -0,0 +1,160 @@
<?php
use Laravel\Fortify\Features;
return [
/*
|--------------------------------------------------------------------------
| Fortify Guard
|--------------------------------------------------------------------------
|
| Here you may specify which authentication guard Fortify will use while
| authenticating users. This value should correspond with one of your
| guards that is already present in your "auth" configuration file.
|
*/
'guard' => 'web',
/*
|--------------------------------------------------------------------------
| Fortify Password Broker
|--------------------------------------------------------------------------
|
| Here you may specify which password broker Fortify can use when a user
| is resetting their password. This configured value should match one
| of your password brokers setup in your "auth" configuration file.
|
*/
'passwords' => 'users',
/*
|--------------------------------------------------------------------------
| Username / Email
|--------------------------------------------------------------------------
|
| This value defines which model attribute should be considered as your
| application's "username" field. Typically, this might be the email
| address of the users but you are free to change this value here.
|
| Out of the box, Fortify expects forgot password and reset password
| requests to have a field named 'email'. If the application uses
| another name for the field you may define it below as needed.
|
*/
'username' => 'USER_ID', // 기본 로그인 필드 변경
'password' => 'USER_PWD', // 기본 비밀번호 필드 변경
'email' => 'email',
/*
|--------------------------------------------------------------------------
| Lowercase Usernames
|--------------------------------------------------------------------------
|
| This value defines whether usernames should be lowercased before saving
| them in the database, as some database system string fields are case
| sensitive. You may disable this for your application if necessary.
|
*/
'lowercase_usernames' => true,
/*
|--------------------------------------------------------------------------
| Home Path
|--------------------------------------------------------------------------
|
| Here you may configure the path where users will get redirected during
| authentication or password reset when the operations are successful
| and the user is authenticated. You are free to change this value.
|
*/
'home' => '/dashboard',
/*
|--------------------------------------------------------------------------
| Fortify Routes Prefix / Subdomain
|--------------------------------------------------------------------------
|
| Here you may specify which prefix Fortify will assign to all the routes
| that it registers with the application. If necessary, you may change
| subdomain under which all of the Fortify routes will be available.
|
*/
'prefix' => '',
'domain' => null,
/*
|--------------------------------------------------------------------------
| Fortify Routes Middleware
|--------------------------------------------------------------------------
|
| Here you may specify which middleware Fortify will assign to the routes
| that it registers with the application. If necessary, you may change
| these middleware but typically this provided default is preferred.
|
*/
'middleware' => ['web'],
/*
|--------------------------------------------------------------------------
| Rate Limiting
|--------------------------------------------------------------------------
|
| By default, Fortify will throttle logins to five requests per minute for
| every email and IP address combination. However, if you would like to
| specify a custom rate limiter to call then you may specify it here.
|
*/
'limiters' => [
'login' => 'login',
'two-factor' => 'two-factor',
],
/*
|--------------------------------------------------------------------------
| Register View Routes
|--------------------------------------------------------------------------
|
| Here you may specify if the routes returning views should be disabled as
| you may not need them when building your own application. This may be
| especially true if you're writing a custom single-page application.
|
*/
'views' => true,
/*
|--------------------------------------------------------------------------
| Features
|--------------------------------------------------------------------------
|
| Some of the Fortify features are optional. You may disable the features
| by removing them from this array. You're free to only remove some of
| these features or you can even remove all of these if you need to.
|
*/
'features' => [
Features::registration(),
Features::resetPasswords(),
// Features::emailVerification(),
Features::updateProfileInformation(),
Features::updatePasswords(),
Features::twoFactorAuthentication([
'confirm' => true,
'confirmPassword' => true,
// 'window' => 0,
]),
],
];

81
config/jetstream.php Normal file
View File

@@ -0,0 +1,81 @@
<?php
use Laravel\Jetstream\Features;
use Laravel\Jetstream\Http\Middleware\AuthenticateSession;
return [
/*
|--------------------------------------------------------------------------
| Jetstream Stack
|--------------------------------------------------------------------------
|
| This configuration value informs Jetstream which "stack" you will be
| using for your application. In general, this value is set for you
| during installation and will not need to be changed after that.
|
*/
'stack' => 'livewire',
/*
|--------------------------------------------------------------------------
| Jetstream Route Middleware
|--------------------------------------------------------------------------
|
| Here you may specify which middleware Jetstream will assign to the routes
| that it registers with the application. When necessary, you may modify
| these middleware; however, this default value is usually sufficient.
|
*/
'middleware' => ['web'],
'auth_session' => AuthenticateSession::class,
/*
|--------------------------------------------------------------------------
| Jetstream Guard
|--------------------------------------------------------------------------
|
| Here you may specify the authentication guard Jetstream will use while
| authenticating users. This value should correspond with one of your
| guards that is already present in your "auth" configuration file.
|
*/
'guard' => 'sanctum',
/*
|--------------------------------------------------------------------------
| Features
|--------------------------------------------------------------------------
|
| Some of Jetstream's features are optional. You may disable the features
| by removing them from this array. You're free to only remove some of
| these features or you can even remove all of these if you need to.
|
*/
'features' => [
// Features::termsAndPrivacyPolicy(),
// Features::profilePhotos(),
// Features::api(),
// Features::teams(['invitations' => true]),
Features::accountDeletion(),
],
/*
|--------------------------------------------------------------------------
| Profile Photo Disk
|--------------------------------------------------------------------------
|
| This configuration value determines the default disk that will be used
| when storing profile photos for your application's users. Typically
| this will be the "public" disk but you may adjust this if needed.
|
*/
'profile_photo_disk' => 'public',
];

283
config/l5-swagger.php Normal file
View File

@@ -0,0 +1,283 @@
<?php
return [
'default' => 'default',
'documentations' => [
'default' => [
'api' => [
'title' => 'L5 Swagger UI',
'version' => '1.0.0',
'default' => env('L5_SWAGGER_DEFAULT_API', '/api/documentation'),
],
'routes' => [
/*
* Route for accessing api documentation interface
*/
'api' => 'api/documentation',
],
'paths' => [
/*
* Edit to include full URL in ui for assets
*/
'use_absolute_path' => env('L5_SWAGGER_USE_ABSOLUTE_PATH', true),
/*
* Edit to set path where swagger ui assets should be stored
*/
'swagger_ui_assets_path' => env('L5_SWAGGER_UI_ASSETS_PATH', 'vendor/swagger-api/swagger-ui/dist/'),
/*
* File name of the generated json documentation file
*/
'docs_json' => 'api-docs.json',
/*
* File name of the generated YAML documentation file
*/
'docs_yaml' => 'api-docs.yaml',
'docs' => 'storage/api-docs',
/*
* Set this to `json` or `yaml` to determine which documentation file to use in UI
*/
'format_to_use_for_docs' => env('L5_FORMAT_TO_USE_FOR_DOCS', 'json'),
/*
* Absolute paths to directory containing the swagger annotations are stored.
*/
'annotations' => [
base_path('app'),
],
],
],
],
'defaults' => [
'routes' => [
/*
* Route for accessing parsed swagger annotations.
*/
'docs' => 'docs',
/*
* Route for Oauth2 authentication callback.
*/
'oauth2_callback' => 'api/oauth2-callback',
/*
* Middleware allows to prevent unexpected access to API documentation
*/
'middleware' => [
'api' => [],
'asset' => [],
'docs' => [],
'oauth2_callback' => [],
],
/*
* Route Group options
*/
'group_options' => [],
],
'paths' => [
/*
* Absolute path to location where parsed annotations will be stored
*/
'docs' => storage_path('api-docs'),
/*
* Absolute path to directory where to export views
*/
'views' => base_path('resources/views/vendor/l5-swagger'),
/*
* Edit to set the api's base path
*/
'base' => env('L5_SWAGGER_BASE_PATH', null),
/*
* Absolute path to directories that should be excluded from scanning
* @deprecated Please use `scanOptions.exclude`
* `scanOptions.exclude` overwrites this
*/
'excludes' => [],
],
'scanOptions' => [
/**
* Configuration for default processors. Allows to pass processors configuration to swagger-php.
*
* @link https://zircote.github.io/swagger-php/reference/processors.html
*/
'default_processors_configuration' => [
/** Example */
/**
* 'operationId.hash' => true,
* 'pathFilter' => [
* 'tags' => [
* '/pets/',
* '/store/',
* ],
* ],.
*/
],
/**
* analyser: defaults to \OpenApi\StaticAnalyser .
*
* @see \OpenApi\scan
*/
'analyser' => null,
/**
* analysis: defaults to a new \OpenApi\Analysis .
*
* @see \OpenApi\scan
*/
'analysis' => null,
/**
* Custom query path processors classes.
*
* @link https://github.com/zircote/swagger-php/tree/master/Examples/processors/schema-query-parameter
* @see \OpenApi\scan
*/
'processors' => [
// new \App\SwaggerProcessors\SchemaQueryParameter(),
],
/**
* pattern: string $pattern File pattern(s) to scan (default: *.php) .
*
* @see \OpenApi\scan
*/
'pattern' => null,
/*
* Absolute path to directories that should be excluded from scanning
* @note This option overwrites `paths.excludes`
* @see \OpenApi\scan
*/
'exclude' => [],
/*
* Allows to generate specs either for OpenAPI 3.0.0 or OpenAPI 3.1.0.
* By default the spec will be in version 3.0.0
*/
'open_api_spec_version' => env('L5_SWAGGER_OPEN_API_SPEC_VERSION', \L5Swagger\Generator::OPEN_API_DEFAULT_SPEC_VERSION),
],
/*
* API security definitions. Will be generated into documentation file.
*/
'securityDefinitions' => [
'ApiKeyAuth' => [
'type' => 'apiKey',
'in' => 'header',
'name' => 'X-API-KEY',
'description' => 'API Key 인증: X-API-KEY: {API_KEY}}',
],
'securitySchemes' => [
'ApiKeyAuth' => [
'type' => 'apiKey',
'in' => 'header',
'name' => 'X-API-KEY',
'description' => 'API Key 인증: X-API-KEY: {API_KEY}}',
],
],
],
'security' => [
[
'ApiKeyAuth' => []
],
],
/*
* Set this to `true` in development mode so that docs would be regenerated on each request
* Set this to `false` to disable swagger generation on production
*/
'generate_always' => env('L5_SWAGGER_GENERATE_ALWAYS', false),
/*
* Set this to `true` to generate a copy of documentation in yaml format
*/
'generate_yaml_copy' => env('L5_SWAGGER_GENERATE_YAML_COPY', false),
/*
* Edit to trust the proxy's ip address - needed for AWS Load Balancer
* string[]
*/
'proxy' => false,
/*
* Configs plugin allows to fetch external configs instead of passing them to SwaggerUIBundle.
* See more at: https://github.com/swagger-api/swagger-ui#configs-plugin
*/
'additional_config_url' => null,
/*
* Apply a sort to the operation list of each API. It can be 'alpha' (sort by paths alphanumerically),
* 'method' (sort by HTTP method).
* Default is the order returned by the server unchanged.
*/
'operations_sort' => env('L5_SWAGGER_OPERATIONS_SORT', null),
/*
* Pass the validatorUrl parameter to SwaggerUi init on the JS side.
* A null value here disables validation.
*/
'validator_url' => null,
/*
* Swagger UI configuration parameters
*/
'ui' => [
'display' => [
'dark_mode' => env('L5_SWAGGER_UI_DARK_MODE', false),
/*
* Controls the default expansion setting for the operations and tags. It can be :
* 'list' (expands only the tags),
* 'full' (expands the tags and operations),
* 'none' (expands nothing).
*/
'doc_expansion' => env('L5_SWAGGER_UI_DOC_EXPANSION', 'none'),
/**
* If set, enables filtering. The top bar will show an edit box that
* you can use to filter the tagged operations that are shown. Can be
* Boolean to enable or disable, or a string, in which case filtering
* will be enabled using that string as the filter expression. Filtering
* is case-sensitive matching the filter expression anywhere inside
* the tag.
*/
'filter' => env('L5_SWAGGER_UI_FILTERS', true), // true | false
],
'authorization' => [
/*
* If set to true, it persists authorization data, and it would not be lost on browser close/refresh
*/
'persist_authorization' => env('L5_SWAGGER_UI_PERSIST_AUTHORIZATION', false),
'oauth2' => [
/*
* If set to true, adds PKCE to AuthorizationCodeGrant flow
*/
'use_pkce_with_authorization_code_grant' => false,
],
],
],
/*
* Constants which can be used in annotations
*/
'constants' => [
'L5_SWAGGER_CONST_HOST' => env('L5_SWAGGER_CONST_HOST', 'http://my-default-host.com'),
],
],
];

160
config/livewire.php Normal file
View File

@@ -0,0 +1,160 @@
<?php
return [
/*
|---------------------------------------------------------------------------
| Class Namespace
|---------------------------------------------------------------------------
|
| This value sets the root class namespace for Livewire component classes in
| your application. This value will change where component auto-discovery
| finds components. It's also referenced by the file creation commands.
|
*/
'class_namespace' => 'App\\Livewire',
/*
|---------------------------------------------------------------------------
| View Path
|---------------------------------------------------------------------------
|
| This value is used to specify where Livewire component Blade templates are
| stored when running file creation commands like `artisan make:livewire`.
| It is also used if you choose to omit a component's render() method.
|
*/
'view_path' => resource_path('views/livewire'),
/*
|---------------------------------------------------------------------------
| Layout
|---------------------------------------------------------------------------
| The view that will be used as the layout when rendering a single component
| as an entire page via `Route::get('/post/create', CreatePost::class);`.
| In this case, the view returned by CreatePost will render into $slot.
|
*/
'layout' => 'components.layouts.app',
/*
|---------------------------------------------------------------------------
| Lazy Loading Placeholder
|---------------------------------------------------------------------------
| Livewire allows you to lazy load components that would otherwise slow down
| the initial page load. Every component can have a custom placeholder or
| you can define the default placeholder view for all components below.
|
*/
'lazy_placeholder' => null,
/*
|---------------------------------------------------------------------------
| Temporary File Uploads
|---------------------------------------------------------------------------
|
| Livewire handles file uploads by storing uploads in a temporary directory
| before the file is stored permanently. All file uploads are directed to
| a global endpoint for temporary storage. You may configure this below:
|
*/
'temporary_file_upload' => [
'disk' => null, // Example: 'local', 's3' | Default: 'default'
'rules' => null, // Example: ['file', 'mimes:png,jpg'] | Default: ['required', 'file', 'max:12288'] (12MB)
'directory' => null, // Example: 'tmp' | Default: 'livewire-tmp'
'middleware' => null, // Example: 'throttle:5,1' | Default: 'throttle:60,1'
'preview_mimes' => [ // Supported file types for temporary pre-signed file URLs...
'png', 'gif', 'bmp', 'svg', 'wav', 'mp4',
'mov', 'avi', 'wmv', 'mp3', 'm4a',
'jpg', 'jpeg', 'mpga', 'webp', 'wma',
],
'max_upload_time' => 5, // Max duration (in minutes) before an upload is invalidated...
'cleanup' => true, // Should cleanup temporary uploads older than 24 hrs...
],
/*
|---------------------------------------------------------------------------
| Render On Redirect
|---------------------------------------------------------------------------
|
| This value determines if Livewire will run a component's `render()` method
| after a redirect has been triggered using something like `redirect(...)`
| Setting this to true will render the view once more before redirecting
|
*/
'render_on_redirect' => false,
/*
|---------------------------------------------------------------------------
| Eloquent Model Binding
|---------------------------------------------------------------------------
|
| Previous versions of Livewire supported binding directly to eloquent model
| properties using wire:model by default. However, this behavior has been
| deemed too "magical" and has therefore been put under a feature flag.
|
*/
'legacy_model_binding' => false,
/*
|---------------------------------------------------------------------------
| Auto-inject Frontend Assets
|---------------------------------------------------------------------------
|
| By default, Livewire automatically injects its JavaScript and CSS into the
| <head> and <body> of pages containing Livewire components. By disabling
| this behavior, you need to use @livewireStyles and @livewireScripts.
|
*/
'inject_assets' => true,
/*
|---------------------------------------------------------------------------
| Navigate (SPA mode)
|---------------------------------------------------------------------------
|
| By adding `wire:navigate` to links in your Livewire application, Livewire
| will prevent the default link handling and instead request those pages
| via AJAX, creating an SPA-like effect. Configure this behavior here.
|
*/
'navigate' => [
'show_progress_bar' => true,
'progress_bar_color' => '#2299dd',
],
/*
|---------------------------------------------------------------------------
| HTML Morph Markers
|---------------------------------------------------------------------------
|
| Livewire intelligently "morphs" existing HTML into the newly rendered HTML
| after each update. To make this process more reliable, Livewire injects
| "markers" into the rendered Blade surrounding @if, @class & @foreach.
|
*/
'inject_morph_markers' => true,
/*
|---------------------------------------------------------------------------
| Pagination Theme
|---------------------------------------------------------------------------
|
| When enabling Livewire's pagination feature by using the `WithPagination`
| trait, Livewire will use Tailwind templates to render pagination views
| on the page. If you want Bootstrap CSS, you can specify: "bootstrap"
|
*/
'pagination_theme' => 'tailwind',
];

132
config/logging.php Normal file
View File

@@ -0,0 +1,132 @@
<?php
use Monolog\Handler\NullHandler;
use Monolog\Handler\StreamHandler;
use Monolog\Handler\SyslogUdpHandler;
use Monolog\Processor\PsrLogMessageProcessor;
return [
/*
|--------------------------------------------------------------------------
| Default Log Channel
|--------------------------------------------------------------------------
|
| This option defines the default log channel that is utilized to write
| messages to your logs. The value provided here should match one of
| the channels present in the list of "channels" configured below.
|
*/
'default' => env('LOG_CHANNEL', 'stack'),
/*
|--------------------------------------------------------------------------
| Deprecations Log Channel
|--------------------------------------------------------------------------
|
| This option controls the log channel that should be used to log warnings
| regarding deprecated PHP and library features. This allows you to get
| your application ready for upcoming major versions of dependencies.
|
*/
'deprecations' => [
'channel' => env('LOG_DEPRECATIONS_CHANNEL', 'null'),
'trace' => env('LOG_DEPRECATIONS_TRACE', false),
],
/*
|--------------------------------------------------------------------------
| Log Channels
|--------------------------------------------------------------------------
|
| Here you may configure the log channels for your application. Laravel
| utilizes the Monolog PHP logging library, which includes a variety
| of powerful log handlers and formatters that you're free to use.
|
| Available drivers: "single", "daily", "slack", "syslog",
| "errorlog", "monolog", "custom", "stack"
|
*/
'channels' => [
'stack' => [
'driver' => 'stack',
'channels' => explode(',', env('LOG_STACK', 'single')),
'ignore_exceptions' => false,
],
'single' => [
'driver' => 'single',
'path' => storage_path('logs/laravel.log'),
'level' => env('LOG_LEVEL', 'debug'),
'replace_placeholders' => true,
],
'daily' => [
'driver' => 'daily',
'path' => storage_path('logs/laravel.log'),
'level' => env('LOG_LEVEL', 'debug'),
'days' => env('LOG_DAILY_DAYS', 14),
'replace_placeholders' => true,
],
'slack' => [
'driver' => 'slack',
'url' => env('LOG_SLACK_WEBHOOK_URL'),
'username' => env('LOG_SLACK_USERNAME', 'Laravel Log'),
'emoji' => env('LOG_SLACK_EMOJI', ':boom:'),
'level' => env('LOG_LEVEL', 'critical'),
'replace_placeholders' => true,
],
'papertrail' => [
'driver' => 'monolog',
'level' => env('LOG_LEVEL', 'debug'),
'handler' => env('LOG_PAPERTRAIL_HANDLER', SyslogUdpHandler::class),
'handler_with' => [
'host' => env('PAPERTRAIL_URL'),
'port' => env('PAPERTRAIL_PORT'),
'connectionString' => 'tls://'.env('PAPERTRAIL_URL').':'.env('PAPERTRAIL_PORT'),
],
'processors' => [PsrLogMessageProcessor::class],
],
'stderr' => [
'driver' => 'monolog',
'level' => env('LOG_LEVEL', 'debug'),
'handler' => StreamHandler::class,
'handler_with' => [
'stream' => 'php://stderr',
],
'formatter' => env('LOG_STDERR_FORMATTER'),
'processors' => [PsrLogMessageProcessor::class],
],
'syslog' => [
'driver' => 'syslog',
'level' => env('LOG_LEVEL', 'debug'),
'facility' => env('LOG_SYSLOG_FACILITY', LOG_USER),
'replace_placeholders' => true,
],
'errorlog' => [
'driver' => 'errorlog',
'level' => env('LOG_LEVEL', 'debug'),
'replace_placeholders' => true,
],
'null' => [
'driver' => 'monolog',
'handler' => NullHandler::class,
],
'emergency' => [
'path' => storage_path('logs/laravel.log'),
],
],
];

116
config/mail.php Normal file
View File

@@ -0,0 +1,116 @@
<?php
return [
/*
|--------------------------------------------------------------------------
| Default Mailer
|--------------------------------------------------------------------------
|
| This option controls the default mailer that is used to send all email
| messages unless another mailer is explicitly specified when sending
| the message. All additional mailers can be configured within the
| "mailers" array. Examples of each type of mailer are provided.
|
*/
'default' => env('MAIL_MAILER', 'log'),
/*
|--------------------------------------------------------------------------
| Mailer Configurations
|--------------------------------------------------------------------------
|
| Here you may configure all of the mailers used by your application plus
| their respective settings. Several examples have been configured for
| you and you are free to add your own as your application requires.
|
| Laravel supports a variety of mail "transport" drivers that can be used
| when delivering an email. You may specify which one you're using for
| your mailers below. You may also add additional mailers if needed.
|
| Supported: "smtp", "sendmail", "mailgun", "ses", "ses-v2",
| "postmark", "resend", "log", "array",
| "failover", "roundrobin"
|
*/
'mailers' => [
'smtp' => [
'transport' => 'smtp',
'scheme' => env('MAIL_SCHEME'),
'url' => env('MAIL_URL'),
'host' => env('MAIL_HOST', '127.0.0.1'),
'port' => env('MAIL_PORT', 2525),
'username' => env('MAIL_USERNAME'),
'password' => env('MAIL_PASSWORD'),
'timeout' => null,
'local_domain' => env('MAIL_EHLO_DOMAIN', parse_url(env('APP_URL', 'http://localhost'), PHP_URL_HOST)),
],
'ses' => [
'transport' => 'ses',
],
'postmark' => [
'transport' => 'postmark',
// 'message_stream_id' => env('POSTMARK_MESSAGE_STREAM_ID'),
// 'client' => [
// 'timeout' => 5,
// ],
],
'resend' => [
'transport' => 'resend',
],
'sendmail' => [
'transport' => 'sendmail',
'path' => env('MAIL_SENDMAIL_PATH', '/usr/sbin/sendmail -bs -i'),
],
'log' => [
'transport' => 'log',
'channel' => env('MAIL_LOG_CHANNEL'),
],
'array' => [
'transport' => 'array',
],
'failover' => [
'transport' => 'failover',
'mailers' => [
'smtp',
'log',
],
],
'roundrobin' => [
'transport' => 'roundrobin',
'mailers' => [
'ses',
'postmark',
],
],
],
/*
|--------------------------------------------------------------------------
| Global "From" Address
|--------------------------------------------------------------------------
|
| You may wish for all emails sent by your application to be sent from
| the same address. Here you may specify a name and address that is
| used globally for all emails that are sent by your application.
|
*/
'from' => [
'address' => env('MAIL_FROM_ADDRESS', 'hello@example.com'),
'name' => env('MAIL_FROM_NAME', 'Example'),
],
];

112
config/queue.php Normal file
View File

@@ -0,0 +1,112 @@
<?php
return [
/*
|--------------------------------------------------------------------------
| Default Queue Connection Name
|--------------------------------------------------------------------------
|
| Laravel's queue supports a variety of backends via a single, unified
| API, giving you convenient access to each backend using identical
| syntax for each. The default queue connection is defined below.
|
*/
'default' => env('QUEUE_CONNECTION', 'database'),
/*
|--------------------------------------------------------------------------
| Queue Connections
|--------------------------------------------------------------------------
|
| Here you may configure the connection options for every queue backend
| used by your application. An example configuration is provided for
| each backend supported by Laravel. You're also free to add more.
|
| Drivers: "sync", "database", "beanstalkd", "sqs", "redis", "null"
|
*/
'connections' => [
'sync' => [
'driver' => 'sync',
],
'database' => [
'driver' => 'database',
'connection' => env('DB_QUEUE_CONNECTION'),
'table' => env('DB_QUEUE_TABLE', 'jobs'),
'queue' => env('DB_QUEUE', 'default'),
'retry_after' => (int) env('DB_QUEUE_RETRY_AFTER', 90),
'after_commit' => false,
],
'beanstalkd' => [
'driver' => 'beanstalkd',
'host' => env('BEANSTALKD_QUEUE_HOST', 'localhost'),
'queue' => env('BEANSTALKD_QUEUE', 'default'),
'retry_after' => (int) env('BEANSTALKD_QUEUE_RETRY_AFTER', 90),
'block_for' => 0,
'after_commit' => false,
],
'sqs' => [
'driver' => 'sqs',
'key' => env('AWS_ACCESS_KEY_ID'),
'secret' => env('AWS_SECRET_ACCESS_KEY'),
'prefix' => env('SQS_PREFIX', 'https://sqs.us-east-1.amazonaws.com/your-account-id'),
'queue' => env('SQS_QUEUE', 'default'),
'suffix' => env('SQS_SUFFIX'),
'region' => env('AWS_DEFAULT_REGION', 'us-east-1'),
'after_commit' => false,
],
'redis' => [
'driver' => 'redis',
'connection' => env('REDIS_QUEUE_CONNECTION', 'default'),
'queue' => env('REDIS_QUEUE', 'default'),
'retry_after' => (int) env('REDIS_QUEUE_RETRY_AFTER', 90),
'block_for' => null,
'after_commit' => false,
],
],
/*
|--------------------------------------------------------------------------
| Job Batching
|--------------------------------------------------------------------------
|
| The following options configure the database and table that store job
| batching information. These options can be updated to any database
| connection and table which has been defined by your application.
|
*/
'batching' => [
'database' => env('DB_CONNECTION', 'sqlite'),
'table' => 'job_batches',
],
/*
|--------------------------------------------------------------------------
| Failed Queue Jobs
|--------------------------------------------------------------------------
|
| These options configure the behavior of failed queue job logging so you
| can control how and where failed jobs are stored. Laravel ships with
| support for storing failed jobs in a simple file or in a database.
|
| Supported drivers: "database-uuids", "dynamodb", "file", "null"
|
*/
'failed' => [
'driver' => env('QUEUE_FAILED_DRIVER', 'database-uuids'),
'database' => env('DB_CONNECTION', 'sqlite'),
'table' => 'failed_jobs',
],
];

83
config/sanctum.php Normal file
View File

@@ -0,0 +1,83 @@
<?php
use Laravel\Sanctum\Sanctum;
return [
/*
|--------------------------------------------------------------------------
| Stateful Domains
|--------------------------------------------------------------------------
|
| Requests from the following domains / hosts will receive stateful API
| authentication cookies. Typically, these should include your local
| and production domains which access your API via a frontend SPA.
|
*/
'stateful' => explode(',', env('SANCTUM_STATEFUL_DOMAINS', sprintf(
'%s%s',
'localhost,localhost:3000,127.0.0.1,127.0.0.1:8000,::1',
Sanctum::currentApplicationUrlWithPort()
))),
/*
|--------------------------------------------------------------------------
| Sanctum Guards
|--------------------------------------------------------------------------
|
| This array contains the authentication guards that will be checked when
| Sanctum is trying to authenticate a request. If none of these guards
| are able to authenticate the request, Sanctum will use the bearer
| token that's present on an incoming request for authentication.
|
*/
'guard' => ['web'],
/*
|--------------------------------------------------------------------------
| Expiration Minutes
|--------------------------------------------------------------------------
|
| This value controls the number of minutes until an issued token will be
| considered expired. This will override any values set in the token's
| "expires_at" attribute, but first-party sessions are not affected.
|
*/
'expiration' => null,
/*
|--------------------------------------------------------------------------
| Token Prefix
|--------------------------------------------------------------------------
|
| Sanctum can prefix new tokens in order to take advantage of numerous
| security scanning initiatives maintained by open source platforms
| that notify developers if they commit tokens into repositories.
|
| See: https://docs.github.com/en/code-security/secret-scanning/about-secret-scanning
|
*/
'token_prefix' => env('SANCTUM_TOKEN_PREFIX', ''),
/*
|--------------------------------------------------------------------------
| Sanctum Middleware
|--------------------------------------------------------------------------
|
| When authenticating your first-party SPA with Sanctum you may need to
| customize some of the middleware Sanctum uses while processing the
| request. You may change the middleware listed below as required.
|
*/
'middleware' => [
'authenticate_session' => Laravel\Sanctum\Http\Middleware\AuthenticateSession::class,
'encrypt_cookies' => Illuminate\Cookie\Middleware\EncryptCookies::class,
'validate_csrf_token' => Illuminate\Foundation\Http\Middleware\ValidateCsrfToken::class,
],
];

38
config/services.php Normal file
View File

@@ -0,0 +1,38 @@
<?php
return [
/*
|--------------------------------------------------------------------------
| Third Party Services
|--------------------------------------------------------------------------
|
| This file is for storing the credentials for third party services such
| as Mailgun, Postmark, AWS and more. This file provides the de facto
| location for this type of information, allowing packages to have
| a conventional file to locate the various service credentials.
|
*/
'postmark' => [
'token' => env('POSTMARK_TOKEN'),
],
'ses' => [
'key' => env('AWS_ACCESS_KEY_ID'),
'secret' => env('AWS_SECRET_ACCESS_KEY'),
'region' => env('AWS_DEFAULT_REGION', 'us-east-1'),
],
'resend' => [
'key' => env('RESEND_KEY'),
],
'slack' => [
'notifications' => [
'bot_user_oauth_token' => env('SLACK_BOT_USER_OAUTH_TOKEN'),
'channel' => env('SLACK_BOT_USER_DEFAULT_CHANNEL'),
],
],
];

217
config/session.php Normal file
View File

@@ -0,0 +1,217 @@
<?php
use Illuminate\Support\Str;
return [
/*
|--------------------------------------------------------------------------
| Default Session Driver
|--------------------------------------------------------------------------
|
| This option determines the default session driver that is utilized for
| incoming requests. Laravel supports a variety of storage options to
| persist session data. Database storage is a great default choice.
|
| Supported: "file", "cookie", "database", "apc",
| "memcached", "redis", "dynamodb", "array"
|
*/
'driver' => env('SESSION_DRIVER', 'database'),
/*
|--------------------------------------------------------------------------
| Session Lifetime
|--------------------------------------------------------------------------
|
| Here you may specify the number of minutes that you wish the session
| to be allowed to remain idle before it expires. If you want them
| to expire immediately when the browser is closed then you may
| indicate that via the expire_on_close configuration option.
|
*/
'lifetime' => (int) env('SESSION_LIFETIME', 120),
'expire_on_close' => env('SESSION_EXPIRE_ON_CLOSE', false),
/*
|--------------------------------------------------------------------------
| Session Encryption
|--------------------------------------------------------------------------
|
| This option allows you to easily specify that all of your session data
| should be encrypted before it's stored. All encryption is performed
| automatically by Laravel and you may use the session like normal.
|
*/
'encrypt' => env('SESSION_ENCRYPT', false),
/*
|--------------------------------------------------------------------------
| Session File Location
|--------------------------------------------------------------------------
|
| When utilizing the "file" session driver, the session files are placed
| on disk. The default storage location is defined here; however, you
| are free to provide another location where they should be stored.
|
*/
'files' => storage_path('framework/sessions'),
/*
|--------------------------------------------------------------------------
| Session Database Connection
|--------------------------------------------------------------------------
|
| When using the "database" or "redis" session drivers, you may specify a
| connection that should be used to manage these sessions. This should
| correspond to a connection in your database configuration options.
|
*/
'connection' => env('SESSION_CONNECTION'),
/*
|--------------------------------------------------------------------------
| Session Database Table
|--------------------------------------------------------------------------
|
| When using the "database" session driver, you may specify the table to
| be used to store sessions. Of course, a sensible default is defined
| for you; however, you're welcome to change this to another table.
|
*/
'table' => env('SESSION_TABLE', 'sessions'),
/*
|--------------------------------------------------------------------------
| Session Cache Store
|--------------------------------------------------------------------------
|
| When using one of the framework's cache driven session backends, you may
| define the cache store which should be used to store the session data
| between requests. This must match one of your defined cache stores.
|
| Affects: "apc", "dynamodb", "memcached", "redis"
|
*/
'store' => env('SESSION_STORE'),
/*
|--------------------------------------------------------------------------
| Session Sweeping Lottery
|--------------------------------------------------------------------------
|
| Some session drivers must manually sweep their storage location to get
| rid of old sessions from storage. Here are the chances that it will
| happen on a given request. By default, the odds are 2 out of 100.
|
*/
'lottery' => [2, 100],
/*
|--------------------------------------------------------------------------
| Session Cookie Name
|--------------------------------------------------------------------------
|
| Here you may change the name of the session cookie that is created by
| the framework. Typically, you should not need to change this value
| since doing so does not grant a meaningful security improvement.
|
*/
'cookie' => env(
'SESSION_COOKIE',
Str::slug(env('APP_NAME', 'laravel'), '_').'_session'
),
/*
|--------------------------------------------------------------------------
| Session Cookie Path
|--------------------------------------------------------------------------
|
| The session cookie path determines the path for which the cookie will
| be regarded as available. Typically, this will be the root path of
| your application, but you're free to change this when necessary.
|
*/
'path' => env('SESSION_PATH', '/'),
/*
|--------------------------------------------------------------------------
| Session Cookie Domain
|--------------------------------------------------------------------------
|
| This value determines the domain and subdomains the session cookie is
| available to. By default, the cookie will be available to the root
| domain and all subdomains. Typically, this shouldn't be changed.
|
*/
'domain' => env('SESSION_DOMAIN'),
/*
|--------------------------------------------------------------------------
| HTTPS Only Cookies
|--------------------------------------------------------------------------
|
| By setting this option to true, session cookies will only be sent back
| to the server if the browser has a HTTPS connection. This will keep
| the cookie from being sent to you when it can't be done securely.
|
*/
'secure' => env('SESSION_SECURE_COOKIE'),
/*
|--------------------------------------------------------------------------
| HTTP Access Only
|--------------------------------------------------------------------------
|
| Setting this value to true will prevent JavaScript from accessing the
| value of the cookie and the cookie will only be accessible through
| the HTTP protocol. It's unlikely you should disable this option.
|
*/
'http_only' => env('SESSION_HTTP_ONLY', true),
/*
|--------------------------------------------------------------------------
| Same-Site Cookies
|--------------------------------------------------------------------------
|
| This option determines how your cookies behave when cross-site requests
| take place, and can be used to mitigate CSRF attacks. By default, we
| will set this value to "lax" to permit secure cross-site requests.
|
| See: https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Set-Cookie#samesitesamesite-value
|
| Supported: "lax", "strict", "none", null
|
*/
'same_site' => env('SESSION_SAME_SITE', 'lax'),
/*
|--------------------------------------------------------------------------
| Partitioned Cookies
|--------------------------------------------------------------------------
|
| Setting this value to true will tie the cookie to the top-level site for
| a cross-site context. Partitioned cookies are accepted by the browser
| when flagged "secure" and the Same-Site attribute is set to "none".
|
*/
'partitioned' => env('SESSION_PARTITIONED_COOKIE', false),
];

1
database/.gitignore vendored Normal file
View File

@@ -0,0 +1 @@
*.sqlite*

View File

@@ -0,0 +1,72 @@
<?php
namespace Database\Factories;
use App\Models\Team;
use App\Models\User;
use Illuminate\Database\Eloquent\Factories\Factory;
use Illuminate\Support\Facades\Hash;
use Illuminate\Support\Str;
use Laravel\Jetstream\Features;
/**
* @extends \Illuminate\Database\Eloquent\Factories\Factory<\App\Models\User>
*/
class UserFactory extends Factory
{
/**
* The current password being used by the factory.
*/
protected static ?string $password;
/**
* Define the model's default state.
*
* @return array<string, mixed>
*/
public function definition(): array
{
return [
'name' => fake()->name(),
'email' => fake()->unique()->safeEmail(),
'email_verified_at' => now(),
'password' => static::$password ??= Hash::make('password'),
'two_factor_secret' => null,
'two_factor_recovery_codes' => null,
'remember_token' => Str::random(10),
'profile_photo_path' => null,
'current_team_id' => null,
];
}
/**
* Indicate that the model's email address should be unverified.
*/
public function unverified(): static
{
return $this->state(fn (array $attributes) => [
'email_verified_at' => null,
]);
}
/**
* Indicate that the user should have a personal team.
*/
public function withPersonalTeam(?callable $callback = null): static
{
if (! Features::hasTeamFeatures()) {
return $this->state([]);
}
return $this->has(
Team::factory()
->state(fn (array $attributes, User $user) => [
'name' => $user->name.'\'s Team',
'user_id' => $user->id,
'personal_team' => true,
])
->when(is_callable($callback), $callback),
'ownedTeams'
);
}
}

View File

@@ -0,0 +1,51 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
/**
* Run the migrations.
*/
public function up(): void
{
Schema::create('users', function (Blueprint $table) {
$table->id();
$table->string('name');
$table->string('email')->unique();
$table->timestamp('email_verified_at')->nullable();
$table->string('password');
$table->rememberToken();
$table->foreignId('current_team_id')->nullable();
$table->string('profile_photo_path', 2048)->nullable();
$table->timestamps();
});
Schema::create('password_reset_tokens', function (Blueprint $table) {
$table->string('email')->primary();
$table->string('token');
$table->timestamp('created_at')->nullable();
});
Schema::create('sessions', function (Blueprint $table) {
$table->string('id')->primary();
$table->foreignId('user_id')->nullable()->index();
$table->string('ip_address', 45)->nullable();
$table->text('user_agent')->nullable();
$table->longText('payload');
$table->integer('last_activity')->index();
});
}
/**
* Reverse the migrations.
*/
public function down(): void
{
Schema::dropIfExists('users');
Schema::dropIfExists('password_reset_tokens');
Schema::dropIfExists('sessions');
}
};

View File

@@ -0,0 +1,35 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
/**
* Run the migrations.
*/
public function up(): void
{
Schema::create('cache', function (Blueprint $table) {
$table->string('key')->primary();
$table->mediumText('value');
$table->integer('expiration');
});
Schema::create('cache_locks', function (Blueprint $table) {
$table->string('key')->primary();
$table->string('owner');
$table->integer('expiration');
});
}
/**
* Reverse the migrations.
*/
public function down(): void
{
Schema::dropIfExists('cache');
Schema::dropIfExists('cache_locks');
}
};

View File

@@ -0,0 +1,57 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
/**
* Run the migrations.
*/
public function up(): void
{
Schema::create('jobs', function (Blueprint $table) {
$table->id();
$table->string('queue')->index();
$table->longText('payload');
$table->unsignedTinyInteger('attempts');
$table->unsignedInteger('reserved_at')->nullable();
$table->unsignedInteger('available_at');
$table->unsignedInteger('created_at');
});
Schema::create('job_batches', function (Blueprint $table) {
$table->string('id')->primary();
$table->string('name');
$table->integer('total_jobs');
$table->integer('pending_jobs');
$table->integer('failed_jobs');
$table->longText('failed_job_ids');
$table->mediumText('options')->nullable();
$table->integer('cancelled_at')->nullable();
$table->integer('created_at');
$table->integer('finished_at')->nullable();
});
Schema::create('failed_jobs', function (Blueprint $table) {
$table->id();
$table->string('uuid')->unique();
$table->text('connection');
$table->text('queue');
$table->longText('payload');
$table->longText('exception');
$table->timestamp('failed_at')->useCurrent();
});
}
/**
* Reverse the migrations.
*/
public function down(): void
{
Schema::dropIfExists('jobs');
Schema::dropIfExists('job_batches');
Schema::dropIfExists('failed_jobs');
}
};

View File

@@ -0,0 +1,42 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
/**
* Run the migrations.
*/
public function up(): void
{
Schema::table('users', function (Blueprint $table) {
$table->text('two_factor_secret')
->after('password')
->nullable();
$table->text('two_factor_recovery_codes')
->after('two_factor_secret')
->nullable();
$table->timestamp('two_factor_confirmed_at')
->after('two_factor_recovery_codes')
->nullable();
});
}
/**
* Reverse the migrations.
*/
public function down(): void
{
Schema::table('users', function (Blueprint $table) {
$table->dropColumn([
'two_factor_secret',
'two_factor_recovery_codes',
'two_factor_confirmed_at',
]);
});
}
};

View File

@@ -0,0 +1,33 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
/**
* Run the migrations.
*/
public function up(): void
{
Schema::create('personal_access_tokens', function (Blueprint $table) {
$table->id();
$table->morphs('tokenable');
$table->string('name');
$table->string('token', 64)->unique();
$table->text('abilities')->nullable();
$table->timestamp('last_used_at')->nullable();
$table->timestamp('expires_at')->nullable();
$table->timestamps();
});
}
/**
* Reverse the migrations.
*/
public function down(): void
{
Schema::dropIfExists('personal_access_tokens');
}
};

View File

@@ -0,0 +1,30 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
/**
* Run the migrations.
*/
public function up(): void
{
Schema::create('api_keys', function (Blueprint $table) {
$table->id();
$table->string('key')->unique(); // API Key
$table->string('description')->nullable(); // 용도 설명 등
$table->boolean('is_active')->default(true); // 키 활성 여부
$table->timestamps();
});
}
/**
* Reverse the migrations.
*/
public function down(): void
{
Schema::dropIfExists('api_keys');
}
};

View File

@@ -0,0 +1,23 @@
<?php
namespace Database\Seeders;
use App\Models\User;
// use Illuminate\Database\Console\Seeds\WithoutModelEvents;
use Illuminate\Database\Seeder;
class DatabaseSeeder extends Seeder
{
/**
* Seed the application's database.
*/
public function run(): void
{
// User::factory(10)->create();
User::factory()->create([
'name' => 'Test User',
'email' => 'test@example.com',
]);
}
}

33
docs/api-docs.json Normal file
View File

@@ -0,0 +1,33 @@
{
"openapi": "3.0.0",
"info": {
"title": "SAM API Documentation",
"description": "SAM(Semi-Automatics Management) API 입니다.",
"contact": {
"email": "shine1324@gmail.com"
},
"version": "1.0.0"
},
"servers": [
{
"url": "https://api.5130.co.kr",
"description": "SAM API 서버"
},
{
"url": "/api"
}
],
"paths": {
"/test": {
"get": {
"summary": "API 테스트 엔드포인트",
"operationId": "bf9b146e21b1276a3e98214e036f0bde",
"responses": {
"200": {
"description": "성공 응답"
}
}
}
}
}
}

20
package.json Normal file
View File

@@ -0,0 +1,20 @@
{
"private": true,
"type": "module",
"scripts": {
"build": "vite build",
"dev": "vite"
},
"devDependencies": {
"@tailwindcss/forms": "^0.5.7",
"@tailwindcss/typography": "^0.5.10",
"@tailwindcss/vite": "^4.0.0",
"autoprefixer": "^10.4.16",
"axios": "^1.8.2",
"concurrently": "^9.0.1",
"laravel-vite-plugin": "^1.2.0",
"postcss": "^8.4.32",
"tailwindcss": "^3.4.0",
"vite": "^6.0.11"
}
}

33
phpunit.xml Normal file
View File

@@ -0,0 +1,33 @@
<?xml version="1.0" encoding="UTF-8"?>
<phpunit xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="vendor/phpunit/phpunit/phpunit.xsd"
bootstrap="vendor/autoload.php"
colors="true"
>
<testsuites>
<testsuite name="Unit">
<directory>tests/Unit</directory>
</testsuite>
<testsuite name="Feature">
<directory>tests/Feature</directory>
</testsuite>
</testsuites>
<source>
<include>
<directory>app</directory>
</include>
</source>
<php>
<env name="APP_ENV" value="testing"/>
<env name="APP_MAINTENANCE_DRIVER" value="file"/>
<env name="BCRYPT_ROUNDS" value="4"/>
<env name="CACHE_STORE" value="array"/>
<!-- <env name="DB_CONNECTION" value="sqlite"/> -->
<!-- <env name="DB_DATABASE" value=":memory:"/> -->
<env name="MAIL_MAILER" value="array"/>
<env name="PULSE_ENABLED" value="false"/>
<env name="QUEUE_CONNECTION" value="sync"/>
<env name="SESSION_DRIVER" value="array"/>
<env name="TELESCOPE_ENABLED" value="false"/>
</php>
</phpunit>

6
postcss.config.js Normal file
View File

@@ -0,0 +1,6 @@
export default {
plugins: {
tailwindcss: {},
autoprefixer: {},
},
};

25
public/.htaccess Normal file
View File

@@ -0,0 +1,25 @@
<IfModule mod_rewrite.c>
<IfModule mod_negotiation.c>
Options -MultiViews -Indexes
</IfModule>
RewriteEngine On
# Handle Authorization Header
RewriteCond %{HTTP:Authorization} .
RewriteRule .* - [E=HTTP_AUTHORIZATION:%{HTTP:Authorization}]
# Handle X-XSRF-Token Header
RewriteCond %{HTTP:x-xsrf-token} .
RewriteRule .* - [E=HTTP_X_XSRF_TOKEN:%{HTTP:X-XSRF-Token}]
# Redirect Trailing Slashes If Not A Folder...
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_URI} (.+)/$
RewriteRule ^ %1 [L,R=301]
# Send Requests To Front Controller...
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^ index.php [L]
</IfModule>

View File

@@ -0,0 +1,394 @@
.animate0 {
-webkit-animation-duration: .8s;
-webkit-animation-delay: 0s;
-webkit-animation-timing-function: ease;
-webkit-animation-fill-mode: both;
-moz-animation-duration: .8s;
-moz-animation-delay: 0s;
-moz-animation-timing-function: ease;
-moz-animation-fill-mode: both;
-ms-animation-duration: .8s;
-ms-animation-delay: 0s;
-ms-animation-timing-function: ease;
-ms-animation-fill-mode: both;
animation-duration: .8s;
animation-delay: 0s;
animation-timing-function: ease;
animation-fill-mode: both;
}
.animate1{
-webkit-animation-duration: .8s;
-webkit-animation-delay: .2s;
-webkit-animation-timing-function: ease;
-webkit-animation-fill-mode: both;
-moz-animation-duration: .8s;
-moz-animation-delay: .2s;
-moz-animation-timing-function: ease;
-moz-animation-fill-mode: both;
-ms-animation-duration: .8s;
-ms-animation-delay: .2s;
-ms-animation-timing-function: ease;
-ms-animation-fill-mode: both;
animation-duration: .8s;
animation-delay: .2s;
animation-timing-function: ease;
animation-fill-mode: both;
}
.animate2{
-webkit-animation-duration: .8s;
-webkit-animation-delay: .4s;
-webkit-animation-timing-function: ease;
-webkit-animation-fill-mode: both;
-moz-animation-duration: .8s;
-moz-animation-delay: .4s;
-moz-animation-timing-function: ease;
-moz-animation-fill-mode: both;
-ms-animation-duration: .8s;
-ms-animation-delay: .4s;
-ms-animation-timing-function: ease;
-ms-animation-fill-mode: both;
animation-duration: .8s;
animation-delay: .4s;
animation-timing-function: ease;
animation-fill-mode: both;
}
.animate3{
-webkit-animation-duration: .8s;
-webkit-animation-delay: .6s;
-webkit-animation-timing-function: ease;
-webkit-animation-fill-mode: both;
-moz-animation-duration: .8s;
-moz-animation-delay: .6s;
-moz-animation-timing-function: ease;
-moz-animation-fill-mode: both;
-ms-animation-duration: .8s;
-ms-animation-delay: .6s;
-ms-animation-timing-function: ease;
-ms-animation-fill-mode: both;
animation-duration: .8s;
animation-delay: .6s;
animation-timing-function: ease;
animation-fill-mode: both;
}
.animate4{
-webkit-animation-duration: .8s;
-webkit-animation-delay: .8s;
-webkit-animation-timing-function: ease;
-webkit-animation-fill-mode: both;
-moz-animation-duration: .8s;
-moz-animation-delay: .8s;
-moz-animation-timing-function: ease;
-moz-animation-fill-mode: both;
-ms-animation-duration: .8s;
-ms-animation-delay: .8s;
-ms-animation-timing-function: ease;
-ms-animation-fill-mode: both;
animation-duration: .8s;
animation-delay: .8s;
animation-timing-function: ease;
animation-fill-mode: both;
}
.animate5{
-webkit-animation-duration: .8s;
-webkit-animation-delay: 1s;
-webkit-animation-timing-function: ease;
-webkit-animation-fill-mode: both;
-moz-animation-duration: .8s;
-moz-animation-delay: 1s;
-moz-animation-timing-function: ease;
-moz-animation-fill-mode: both;
-ms-animation-duration: .8s;
-ms-animation-delay: 1s;
-ms-animation-timing-function: ease;
-ms-animation-fill-mode: both;
animation-duration: .8s;
animation-delay: 1s;
animation-timing-function: ease;
animation-fill-mode: both;
}
.animate6{
-webkit-animation-duration: .8s;
-webkit-animation-delay: 1.2s;
-webkit-animation-timing-function: ease;
-webkit-animation-fill-mode: both;
-moz-animation-duration: .8s;
-moz-animation-delay: 1.2s;
-moz-animation-timing-function: ease;
-moz-animation-fill-mode: both;
-ms-animation-duration: .8s;
-ms-animation-delay: 1.2s;
-ms-animation-timing-function: ease;
-ms-animation-fill-mode: both;
animation-duration: .8s;
animation-delay: 1.2s;
animation-timing-function: ease;
animation-fill-mode: both;
}
.animate7{
-webkit-animation-duration: .8s;
-webkit-animation-delay: 1.4s;
-webkit-animation-timing-function: ease;
-webkit-animation-fill-mode: both;
-moz-animation-duration: .8s;
-moz-animation-delay: 1.4s;
-moz-animation-timing-function: ease;
-moz-animation-fill-mode: both;
-ms-animation-duration: .8s;
-ms-animation-delay: 1.4s;
-ms-animation-timing-function: ease;
-ms-animation-fill-mode: both;
animation-duration: .8s;
animation-delay: 1.4s;
animation-timing-function: ease;
animation-fill-mode: both;
}
.animate8{
-webkit-animation-duration: .8s;
-webkit-animation-delay: 1.8s;
-webkit-animation-timing-function: ease;
-webkit-animation-fill-mode: both;
-moz-animation-duration: .8s;
-moz-animation-delay: 1.8s;
-moz-animation-timing-function: ease;
-moz-animation-fill-mode: both;
-ms-animation-duration: .8s;
-ms-animation-delay: 1.8s;
-ms-animation-timing-function: ease;
-ms-animation-fill-mode: both;
animation-duration: .8s;
animation-delay: 1.8s;
animation-timing-function: ease;
animation-fill-mode: both;
}
.animate9{
-webkit-animation-duration: .8s;
-webkit-animation-delay: 1.8s;
-webkit-animation-timing-function: ease;
-webkit-animation-fill-mode: both;
-moz-animation-duration: .8s;
-moz-animation-delay: 1.8s;
-moz-animation-timing-function: ease;
-moz-animation-fill-mode: both;
-ms-animation-duration: .8s;
-ms-animation-delay: 1.8s;
-ms-animation-timing-function: ease;
-ms-animation-fill-mode: both;
animation-duration: .8s;
animation-delay: 1.8s;
animation-timing-function: ease;
animation-fill-mode: both;
}
.animate10{
-webkit-animation-duration: .8s;
-webkit-animation-delay: 2.0s;
-webkit-animation-timing-function: ease;
-webkit-animation-fill-mode: both;
-moz-animation-duration: .8s;
-moz-animation-delay: 2.0s;
-moz-animation-timing-function: ease;
-moz-animation-fill-mode: both;
-ms-animation-duration: .8s;
-ms-animation-delay: 2.0s;
-ms-animation-timing-function: ease;
-ms-animation-fill-mode: both;
animation-duration: .8s;
animation-delay: 2.0s;
animation-timing-function: ease;
animation-fill-mode: both;
}
.animate11{
-webkit-animation-duration: .8s;
-webkit-animation-delay: 2.2s;
-webkit-animation-timing-function: ease;
-webkit-animation-fill-mode: both;
-moz-animation-duration: .8s;
-moz-animation-delay: 2.2s;
-moz-animation-timing-function: ease;
-moz-animation-fill-mode: both;
-ms-animation-duration: .8s;
-ms-animation-delay: 2.2s;
-ms-animation-timing-function: ease;
-ms-animation-fill-mode: both;
animation-duration: .8s;
animation-delay: 2.2s;
animation-timing-function: ease;
animation-fill-mode: both;
}
.animate12{
-webkit-animation-duration: .8s;
-webkit-animation-delay: 2.4s;
-webkit-animation-timing-function: ease;
-webkit-animation-fill-mode: both;
-moz-animation-duration: .8s;
-moz-animation-delay: 2.4s;
-moz-animation-timing-function: ease;
-moz-animation-fill-mode: both;
-ms-animation-duration: .8s;
-ms-animation-delay: 2.4s;
-ms-animation-timing-function: ease;
-ms-animation-fill-mode: both;
animation-duration: .8s;
animation-delay: 2.4s;
animation-timing-function: ease;
animation-fill-mode: both;
}
.animate13{
-webkit-animation-duration: .8s;
-webkit-animation-delay: 2.8s;
-webkit-animation-timing-function: ease;
-webkit-animation-fill-mode: both;
-moz-animation-duration: .8s;
-moz-animation-delay: 2.8s;
-moz-animation-timing-function: ease;
-moz-animation-fill-mode: both;
-ms-animation-duration: .8s;
-ms-animation-delay: 2.8s;
-ms-animation-timing-function: ease;
-ms-animation-fill-mode: both;
animation-duration: .8s;
animation-delay: 2.8s;
animation-timing-function: ease;
animation-fill-mode: both;
}
.animate14{
-webkit-animation-duration: .8s;
-webkit-animation-delay: 2.8s;
-webkit-animation-timing-function: ease;
-webkit-animation-fill-mode: both;
-moz-animation-duration: .8s;
-moz-animation-delay: 2.8s;
-moz-animation-timing-function: ease;
-moz-animation-fill-mode: both;
-ms-animation-duration: .8s;
-ms-animation-delay: 2.8s;
-ms-animation-timing-function: ease;
-ms-animation-fill-mode: both;
animation-duration: .8s;
animation-delay: 2.8s;
animation-timing-function: ease;
animation-fill-mode: both;
}
.animate15{
-webkit-animation-duration: .8s;
-webkit-animation-delay: 3.0s;
-webkit-animation-timing-function: ease;
-webkit-animation-fill-mode: both;
-moz-animation-duration: .8s;
-moz-animation-delay: 3.0s;
-moz-animation-timing-function: ease;
-moz-animation-fill-mode: both;
-ms-animation-duration: .8s;
-ms-animation-delay: 3.0s;
-ms-animation-timing-function: ease;
-ms-animation-fill-mode: both;
animation-duration: .8s;
animation-delay: 3.0s;
animation-timing-function: ease;
animation-fill-mode: both;
}
.animate16{
-webkit-animation-duration: .8s;
-webkit-animation-delay: 3.2s;
-webkit-animation-timing-function: ease;
-webkit-animation-fill-mode: both;
-moz-animation-duration: .8s;
-moz-animation-delay: 3.2s;
-moz-animation-timing-function: ease;
-moz-animation-fill-mode: both;
-ms-animation-duration: .8s;
-ms-animation-delay: 3.2s;
-ms-animation-timing-function: ease;
-ms-animation-fill-mode: both;
animation-duration: .8s;
animation-delay: 3.2s;
animation-timing-function: ease;
animation-fill-mode: both;
}
.animate17{
-webkit-animation-duration: .8s;
-webkit-animation-delay: 3.4s;
-webkit-animation-timing-function: ease;
-webkit-animation-fill-mode: both;
-moz-animation-duration: .8s;
-moz-animation-delay: 3.4s;
-moz-animation-timing-function: ease;
-moz-animation-fill-mode: both;
-ms-animation-duration: .8s;
-ms-animation-delay: 3.4s;
-ms-animation-timing-function: ease;
-ms-animation-fill-mode: both;
animation-duration: .8s;
animation-delay: 3.4s;
animation-timing-function: ease;
animation-fill-mode: both;
}
.animate18{
-webkit-animation-duration: .8s;
-webkit-animation-delay: 3.6s;
-webkit-animation-timing-function: ease;
-webkit-animation-fill-mode: both;
-moz-animation-duration: .8s;
-moz-animation-delay: 3.6s;
-moz-animation-timing-function: ease;
-moz-animation-fill-mode: both;
-ms-animation-duration: .8s;
-ms-animation-delay: 3.6s;
-ms-animation-timing-function: ease;
-ms-animation-fill-mode: both;
animation-duration: .8s;
animation-delay: 3.6s;
animation-timing-function: ease;
animation-fill-mode: both;
}
.animate19{
-webkit-animation-duration: .8s;
-webkit-animation-delay: 3.8s;
-webkit-animation-timing-function: ease;
-webkit-animation-fill-mode: both;
-moz-animation-duration: .8s;
-moz-animation-delay: 3.8s;
-moz-animation-timing-function: ease;
-moz-animation-fill-mode: both;
-ms-animation-duration: .8s;
-ms-animation-delay: 3.8s;
-ms-animation-timing-function: ease;
-ms-animation-fill-mode: both;
animation-duration: .8s;
animation-delay: 3.8s;
animation-timing-function: ease;
animation-fill-mode: both;
}
.animate20{
-webkit-animation-duration: .8s;
-webkit-animation-delay: 4.0s;
-webkit-animation-timing-function: ease;
-webkit-animation-fill-mode: both;
-moz-animation-duration: .8s;
-moz-animation-delay: 4.0s;
-moz-animation-timing-function: ease;
-moz-animation-fill-mode: both;
-ms-animation-duration: .8s;
-ms-animation-delay: 4.0s;
-ms-animation-timing-function: ease;
-ms-animation-fill-mode: both;
animation-duration: .8s;
animation-delay: 4.0s;
animation-timing-function: ease;
animation-fill-mode: both;
}

1
public/admin/css/animate.min.css vendored Normal file

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,36 @@
/*!
* Bootstrap v2.3.0-j4
*
* Copyright 2012 Twitter, Inc
* Licensed under the Apache License v2.0
* http://www.apache.org/licenses/LICENSE-2.0
*
* Designed and built with all the love in the world by @mdo and @fat, extended by @ArnoldDaniels.
*/
.clearfix{*zoom:1;}.clearfix:before,.clearfix:after{display:table;content:"";line-height:0;}
.clearfix:after{clear:both;}
.hide-text{font:0/0 a;color:transparent;text-shadow:none;background-color:transparent;border:0;}
.input-block-level{display:block;width:100%;min-height:30px;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;}
.btn-file{overflow:hidden;position:relative;vertical-align:middle;}.btn-file>input{position:absolute;top:0;right:0;margin:0;opacity:0;filter:alpha(opacity=0);transform:translate(-300px, 0) scale(4);font-size:23px;direction:ltr;cursor:pointer;}
.fileupload .uneditable-input{display:inline-block;margin-bottom:0px;vertical-align:middle;cursor:text;background: #fff;}
.fileupload .thumbnail{overflow:hidden;display:inline-block;margin-bottom:5px;vertical-align:middle;text-align:center;}.fileupload .thumbnail>img{display:inline-block;vertical-align:middle;max-height:100%;}
.fileupload .btn{vertical-align:middle; line-height: 21px; margin-left: -5px; }
.fileupload-exists .fileupload-new,.fileupload-new .fileupload-exists{display:none;}
.fileupload-inline .fileupload-controls{display:inline;}
.fileupload-new .input-append .btn-file{-webkit-border-radius:0 2px 2px 0;-moz-border-radius:0 2px 2px 0;border-radius:0 2px 2px 0;}
.thumbnail-borderless .thumbnail{border:none;padding:0;-webkit-border-radius:0;-moz-border-radius:0;border-radius:0;-webkit-box-shadow:none;-moz-box-shadow:none;box-shadow:none;}
.fileupload-new.thumbnail-borderless .thumbnail{border:1px solid #ddd;}
.control-group.warning .fileupload .uneditable-input{color:#a47e3c;border-color:#a47e3c;}
.control-group.warning .fileupload .fileupload-preview{color:#a47e3c;}
.control-group.warning .fileupload .thumbnail{border-color:#a47e3c;}
.control-group.error .fileupload .uneditable-input{color:#b94a48;border-color:#b94a48;}
.control-group.error .fileupload .fileupload-preview{color:#b94a48;}
.control-group.error .fileupload .thumbnail{border-color:#b94a48;}
.control-group.success .fileupload .uneditable-input{color:#468847;border-color:#468847;}
.control-group.success .fileupload .fileupload-preview{color:#468847;}
.control-group.success .fileupload .thumbnail{border-color:#468847;}
.uneditable-input {
border: 1px solid #ccc; height: 35px; padding: 6px 10px; width: 200px; overflow: hidden;
-moz-border-radius: 2px; -webkit-border-radius: 2px; border-radius: 2px; }
.uneditable-input .glyphicon { float: left; margin-right: 5px; vertical-align: middle; margin-top: 2px; opacity: 0.5; }
.fileupload-preview { width: 400px; display: block; color: #666; }

1300
public/admin/css/bootstrap-override.css vendored Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,10 @@
/*!
* Timepicker Component for Twitter Bootstrap
*
* Copyright 2013 Joris de Wit
*
* Contributors https://github.com/jdewit/bootstrap-timepicker/graphs/contributors
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/.bootstrap-timepicker{position:relative}.bootstrap-timepicker.pull-right .bootstrap-timepicker-widget.dropdown-menu{left:auto;right:0}.bootstrap-timepicker.pull-right .bootstrap-timepicker-widget.dropdown-menu:before{left:auto;right:12px}.bootstrap-timepicker.pull-right .bootstrap-timepicker-widget.dropdown-menu:after{left:auto;right:13px}.bootstrap-timepicker .add-on{cursor:pointer}.bootstrap-timepicker .add-on i{display:inline-block;width:16px;height:16px}.bootstrap-timepicker-widget.dropdown-menu{padding:2px 3px 2px 2px}.bootstrap-timepicker-widget.dropdown-menu.open{display:inline-block}.bootstrap-timepicker-widget.dropdown-menu:before{border-bottom:7px solid rgba(0,0,0,0.2);border-left:7px solid transparent;border-right:7px solid transparent;content:"";display:inline-block;left:9px;position:absolute;top:-7px}.bootstrap-timepicker-widget.dropdown-menu:after{border-bottom:6px solid #fff;border-left:6px solid transparent;border-right:6px solid transparent;content:"";display:inline-block;left:10px;position:absolute;top:-6px}.bootstrap-timepicker-widget a.btn,.bootstrap-timepicker-widget input{border-radius:4px}.bootstrap-timepicker-widget table{width:100%;margin:0}.bootstrap-timepicker-widget table td{text-align:center;height:30px;margin:0;padding:2px}.bootstrap-timepicker-widget table td:not(.separator){min-width:30px}.bootstrap-timepicker-widget table td span{width:100%}.bootstrap-timepicker-widget table td a{border:1px transparent solid;width:100%;display:inline-block;margin:0;padding:8px 0;outline:0;color:#333}.bootstrap-timepicker-widget table td a:hover{text-decoration:none;background-color:#eee;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;border-color:#ddd}.bootstrap-timepicker-widget table td a i{margin-top:2px}.bootstrap-timepicker-widget table td input{width:25px;margin:0;text-align:center}.bootstrap-timepicker-widget .modal-content{padding:4px}@media(min-width:767px){.bootstrap-timepicker-widget.modal{width:200px;margin-left:-100px}}@media(max-width:767px){.bootstrap-timepicker{width:100%}.bootstrap-timepicker .dropdown-menu{width:100%}}

5831
public/admin/css/bootstrap.css vendored Normal file

File diff suppressed because it is too large Load Diff

4537
public/admin/css/bootstrap.min.css vendored Normal file

File diff suppressed because it is too large Load Diff

398
public/admin/css/chosen.css Normal file
View File

@@ -0,0 +1,398 @@
/* @group Base */
.chosen-container {
position: relative;
display: inline-block;
vertical-align: middle;
font-size: 13px;
zoom: 1;
*display: inline;
-webkit-user-select: none;
-moz-user-select: none;
user-select: none;
}
.chosen-container .chosen-drop {
position: absolute;
top: 100%;
left: -9999px;
z-index: 1010;
-webkit-box-sizing: border-box;
-moz-box-sizing: border-box;
box-sizing: border-box;
width: 100%;
border: 1px solid #aaa;
border-top: 0;
background: #fff;
}
.chosen-container.chosen-with-drop .chosen-drop {
left: 0;
}
.chosen-container a {
cursor: pointer;
}
/* @end */
/* @group Single Chosen */
.chosen-container-single .chosen-single {
position: relative;
display: block;
overflow: hidden;
padding: 5px 10px 5px;
border: 1px solid #ccc;
border-radius: 2px;
background-color: #fff;
color: #444;
text-decoration: none;
white-space: nowrap;
line-height: 21px;
}
.chosen-container-single .chosen-default {
color: #999;
}
.chosen-container-single .chosen-single span {
display: block;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.chosen-container-single .chosen-single-with-deselect span {
margin-right: 38px;
}
.chosen-container-single .chosen-single abbr {
position: absolute;
top: 6px;
right: 26px;
display: block;
width: 12px;
height: 12px;
background: url('chosen-sprite.png') -42px 1px no-repeat;
font-size: 1px;
}
.chosen-container-single .chosen-single abbr:hover {
background-position: -42px -10px;
}
.chosen-container-single.chosen-disabled .chosen-single abbr:hover {
background-position: -42px -10px;
}
.chosen-container-single .chosen-single div {
position: absolute;
top: 0;
right: 0;
display: block;
width: 18px;
height: 100%;
}
.chosen-container-single .chosen-single div b {
display: block;
width: 100%;
height: 100%;
background: url('../images/chosen-sprite.png') no-repeat 0px 8px;
}
.chosen-container-single .chosen-search {
position: relative;
z-index: 1010;
margin: 0;
padding: 3px 4px;
white-space: nowrap;
}
.chosen-container-single .chosen-search input[type="text"] {
-webkit-box-sizing: border-box;
-moz-box-sizing: border-box;
box-sizing: border-box;
margin: 1px 0;
padding: 8px 20px 8px 10px;
width: 100%;
height: auto;
outline: 0;
border: 1px solid #aaa;
background: #fff url('../images/icon-search.png') no-repeat 97% center;
font-size: 1em;
font-family: sans-serif;
line-height: normal;
border-radius: 0;
}
.chosen-container-single .chosen-drop {
margin-top: -1px;
border-radius: 0 0 2px 2px;
background-clip: padding-box;
}
.chosen-container-single.chosen-container-single-nosearch .chosen-search {
position: absolute;
left: -9999px;
}
/* @end */
/* @group Results */
.chosen-container .chosen-results {
position: relative;
overflow-x: hidden;
overflow-y: auto;
margin: 0 4px 4px 0;
padding: 0 0 0 4px;
max-height: 240px;
-webkit-overflow-scrolling: touch;
}
.chosen-container .chosen-results li {
display: none;
margin: 0;
padding: 5px 6px;
list-style: none;
line-height: 15px;
}
.chosen-container .chosen-results li.active-result {
display: list-item;
cursor: pointer;
}
.chosen-container .chosen-results li.disabled-result {
display: list-item;
color: #ccc;
cursor: default;
}
.chosen-container .chosen-results li.highlighted {
background-color: #428BCA;
color: #fff;
}
.chosen-container .chosen-results li.no-results {
display: list-item;
background: #f4f4f4;
}
.chosen-container .chosen-results li.group-result {
display: list-item;
font-weight: bold;
cursor: default;
}
.chosen-container .chosen-results li.group-option {
padding-left: 15px;
}
.chosen-container .chosen-results li em {
font-style: normal;
text-decoration: underline;
}
/* @end */
/* @group Multi Chosen */
.chosen-container-multi .chosen-choices {
position: relative;
overflow: hidden;
-webkit-box-sizing: border-box;
-moz-box-sizing: border-box;
box-sizing: border-box;
margin: 0;
padding: 0;
width: 100%;
height: 37px !important;
height: 1%;
border: 1px solid #ccc;
background-color: #fff;
cursor: text;
-moz-border-radis: 2px;
-webkit-border-radius: 2px;
border-radius: 2px;
}
.chosen-container-multi .chosen-choices li {
float: left;
list-style: none;
}
.chosen-container-multi .chosen-choices li.search-field {
margin: 0;
padding: 0;
white-space: nowrap;
}
.chosen-container-multi .chosen-choices li.search-field input[type="text"] {
margin: 1px 0;
padding: 8px 10px;
outline: 0;
border: 0 !important;
background: transparent !important;
box-shadow: none;
color: #666;
font-size: 100%;
font-family: sans-serif;
line-height: normal;
border-radius: 0;
}
.chosen-container-multi .chosen-choices li.search-field .default {
color: #999;
}
.chosen-container-multi .chosen-choices li.search-choice {
position: relative;
margin: 3px 0 3px 3px;
padding: 8px 20px 8px 10px;
-moz-border-radius: 2px;
-webkit-border-radius: 2px;
border-radius: 2px;
background-color: #eee;
background-clip: padding-box;
color: #333;
line-height: 13px;
cursor: default;
font-size: 12px;
}
.chosen-container-multi .chosen-choices li.search-choice .search-choice-close {
position: absolute;
top: 8px;
right: 3px;
display: block;
width: 12px;
height: 12px;
background: url('../images/chosen-sprite.png') -42px 1px no-repeat;
font-size: 1px;
}
.chosen-container-multi .chosen-choices li.search-choice .search-choice-close:hover {
background-position: -42px -10px;
}
.chosen-container-multi .chosen-choices li.search-choice-disabled {
padding-right: 5px;
border: 1px solid #ccc;
background-color: #e4e4e4;
background-image: -webkit-gradient(linear, 50% 0%, 50% 100%, color-stop(20%, #f4f4f4), color-stop(50%, #f0f0f0), color-stop(52%, #e8e8e8), color-stop(100%, #eeeeee));
background-image: -webkit-linear-gradient(top, #f4f4f4 20%, #f0f0f0 50%, #e8e8e8 52%, #eeeeee 100%);
background-image: -moz-linear-gradient(top, #f4f4f4 20%, #f0f0f0 50%, #e8e8e8 52%, #eeeeee 100%);
background-image: -o-linear-gradient(top, #f4f4f4 20%, #f0f0f0 50%, #e8e8e8 52%, #eeeeee 100%);
background-image: linear-gradient(top, #f4f4f4 20%, #f0f0f0 50%, #e8e8e8 52%, #eeeeee 100%);
color: #666;
}
.chosen-container-multi .chosen-choices li.search-choice-focus {
background: #d4d4d4;
}
.chosen-container-multi .chosen-choices li.search-choice-focus .search-choice-close {
background-position: -42px -10px;
}
.chosen-container-multi .chosen-results {
margin: 0;
padding: 0;
}
.chosen-container-multi .chosen-drop .result-selected {
display: list-item;
color: #ccc;
cursor: default;
}
/* @end */
/* @group Active */
.chosen-container-active .chosen-single {
border: 1px solid #bbb;
}
.chosen-container-active.chosen-with-drop .chosen-single {
border: 1px solid #aaa;
-moz-border-radius-bottomright: 0;
border-bottom-right-radius: 0;
-moz-border-radius-bottomleft: 0;
border-bottom-left-radius: 0;
}
.chosen-container-active.chosen-with-drop .chosen-single div {
border-left: none;
background: transparent;
}
.chosen-container-active.chosen-with-drop .chosen-single div b {
background-position: -18px 8px;
}
.chosen-container-active .chosen-choices {
border: 1px solid #bbb;
-moz-border-radius: 2px;
-webkit-border-radius: 2px;
border-radius: 2px;
}
.chosen-container-active .chosen-choices li.search-field input[type="text"] {
color: #111 !important;
}
/* @end */
/* @group Disabled Support */
.chosen-disabled {
opacity: 0.5 !important;
cursor: default;
}
.chosen-disabled .chosen-single {
cursor: default;
}
.chosen-disabled .chosen-choices .search-choice .search-choice-close {
cursor: default;
}
/* @end */
/* @group Right to Left */
.chosen-rtl {
text-align: right;
}
.chosen-rtl .chosen-single {
overflow: visible;
padding: 0 8px 0 0;
}
.chosen-rtl .chosen-single span {
margin-right: 0;
margin-left: 26px;
direction: rtl;
}
.chosen-rtl .chosen-single-with-deselect span {
margin-left: 38px;
}
.chosen-rtl .chosen-single div {
right: auto;
left: 3px;
}
.chosen-rtl .chosen-single abbr {
right: auto;
left: 26px;
}
.chosen-rtl .chosen-choices li {
float: right;
}
.chosen-rtl .chosen-choices li.search-field input[type="text"] {
direction: rtl;
}
.chosen-rtl .chosen-choices li.search-choice {
margin: 3px 5px 3px 0;
padding: 3px 5px 3px 19px;
}
.chosen-rtl .chosen-choices li.search-choice .search-choice-close {
right: auto;
left: 4px;
}
.chosen-rtl.chosen-container-single-nosearch .chosen-search,
.chosen-rtl .chosen-drop {
left: 9999px;
}
.chosen-rtl.chosen-container-single .chosen-results {
margin: 0 0 4px 4px;
padding: 0 4px 0 0;
}
.chosen-rtl .chosen-results li.group-option {
padding-right: 15px;
padding-left: 0;
}
.chosen-rtl.chosen-container-active.chosen-with-drop .chosen-single div {
border-right: none;
}
.chosen-rtl .chosen-search input[type="text"] {
padding: 4px 5px 4px 20px;
background: white url('chosen-sprite.png') no-repeat -30px -20px;
background: url('chosen-sprite.png') no-repeat -30px -20px, -webkit-gradient(linear, 50% 0%, 50% 100%, color-stop(1%, #eeeeee), color-stop(15%, #ffffff));
background: url('chosen-sprite.png') no-repeat -30px -20px, -webkit-linear-gradient(#eeeeee 1%, #ffffff 15%);
background: url('chosen-sprite.png') no-repeat -30px -20px, -moz-linear-gradient(#eeeeee 1%, #ffffff 15%);
background: url('chosen-sprite.png') no-repeat -30px -20px, -o-linear-gradient(#eeeeee 1%, #ffffff 15%);
background: url('chosen-sprite.png') no-repeat -30px -20px, linear-gradient(#eeeeee 1%, #ffffff 15%);
direction: rtl;
}
.chosen-rtl.chosen-container-single .chosen-single div b {
background-position: 6px 2px;
}
.chosen-rtl.chosen-container-single.chosen-with-drop .chosen-single div b {
background-position: -12px 2px;
}
/* @end */
/* @group Retina compatibility */
@media only screen and (-webkit-min-device-pixel-ratio: 2), only screen and (min-resolution: 144dpi) {
.chosen-rtl .chosen-search input[type="text"],
.chosen-container-single .chosen-single abbr,
.chosen-container-single .chosen-single div b,
.chosen-container-single .chosen-search input[type="text"],
.chosen-container-multi .chosen-choices .search-choice .search-choice-close,
.chosen-container .chosen-results-scroll-down span,
.chosen-container .chosen-results-scroll-up span {
background-image: url('chosen-sprite@2x.png') !important;
background-size: 52px 37px !important;
background-repeat: no-repeat !important;
}
}
/* @end */

448
public/admin/css/custom.css Normal file
View File

@@ -0,0 +1,448 @@
/*
css-only-tooltip version 1.0.0
ⓒ 2015 AHN JAE-HA http://github.com/eu81273
MIT License
*/
[data-tooltip-text]:hover {
position: relative;
}
[data-tooltip-text]:hover:after {
background-color: #000000;
background-color: rgba(0, 0, 0, 0.8);
-webkit-box-shadow: 0px 0px 3px 1px rgba(50, 50, 50, 0.4);
-moz-box-shadow: 0px 0px 3px 1px rgba(50, 50, 50, 0.4);
box-shadow: 0px 0px 3px 1px rgba(50, 50, 50, 0.4);
-webkit-border-radius: 5px;
-moz-border-radius: 5px;
border-radius: 5px;
color: #FFFFFF;
font-size: 12px;
content:"캐시키보드1 : " attr(data-tooltip-text) "\A캐시키보드2 : " attr(data-tooltip-text2);
white-space:pre;
margin-bottom: 10px;
top: 130%;
left: 0;
padding: 7px 12px;
position: absolute;
text-align: left;
z-index: 9999;
}
.mngOff {
background-color: #f0f0f0;
}
.progress-group {
display: flex;
align-items: center; /* 세로 축에서 중앙 정렬 */
justify-content: space-between; /* 자식 요소들 사이에 공간을 균등하게 배분 */
margin-bottom: 5px; /* 그룹 간의 여백 */
}
.progress-group:last-child {
margin-bottom: 0; /* 마지막 progress-group에 대한 여백을 제거 */
}
.progressbar-label {
/* 필요한 추가 스타일링 */
flex: 0 0 auto; /* 라벨이 컨텐츠 크기에 따라 크기가 정해지도록 설정 */
margin-right: 5px; /* 라벨과 진행율 바 사이의 여백 */
padding : 0 5px;
width:45px;
}
.progressbar-container {
flex: 1; /* 진행율 바 컨테이너가 남은 공간을 모두 차지하도록 설정 */
width: 0; /* flex: 1 속성을 활성화하기 위해 width를 0으로 설정 */
position: relative;
}
.progressbar-border {
border: 1px solid #ccc;
height: 15px;
position: relative;
overflow: hidden;
}
.progressbar-background {
height: 100%;
background-color: white;
width: 100%;
position: absolute;
top: 0;
left: 0;
}
.progressbar {
position: absolute;
height: 100%;
}
.progress-group2 {
display : none;
}
/*** 이슈관리 > 업무이슈 [S] ***/
#columns{
column-width:350px;
column-gap: 15px;
}
#columns figure{
display: inline-block;
border:1px solid rgba(0,0,0,0.2);
margin:0;
margin-bottom: 15px;
padding:10px;
box-shadow: 2px 2px 5px rgba(0,0,0,0.5);
line-height: 15px;
font-size: 9pt;
color:gray;
width:100%;
}
#columns figure img {
width:100%;
}
.columns-figure-title > span.card-title{
font-size: 10pt;
/*font-weight: bold;*/
line-height: 20px;
}
.columns-figure-title > span.card-date{
color:navy;
padding-left:10px;
line-height: 20px;
}
.columns-figure-title > .repeat{
color: #6666bd;
}
.columns-figure-footer{
display: flex;
flex-wrap: wrap;
}
.columns-figure-footer > div > span{
margin-right:10px;
}
.columns-figure-footer > div > span.strong{
color:navy;
}
.columns-figure-detail{
background: #fffaee;
border:1px solid #faecb9;
border-radius: 5px;
padding:5px;
margin-bottom: 10px;
/*max-height:150px;*/
overflow-y: scroll;
color:gray;
font-size: 9pt;
line-height: 20px;
word-break: break-all;
}
.columns-figure-detail.repeat{
background: #eef7fd;
border:1px solid #d2f2ff;
}
.columns-figure-comment{
padding-bottom: 10px;
}
.columns-figure-comment > .cmt-list{
background: #f4ffe6;
border:1px solid #b2e5b7;
border-radius: 5px;
padding:3px;
color:gray;
margin-top: 3px;
word-break: break-all;
}
.columns-figure-comment > .appendix{
background: white;
border:1px solid #bdbdbd;
border-radius: 5px;
padding:3px 10px;
color:gray;
margin: 0px;
}
.columns-figure-comment > .appendix > span{
color:black;
font-weight: bold;
line-height: 20px;
border:1px solid #c0c0c0;
margin-right:0px;
}
.columns-figure-comment > div > span{
color:black;
font-weight: bold;
line-height: 20px;
}
/*** 이슈관리 > 업무이슈 [E] ***/
/** 회의록 - 파일첨부 [S] **/
.insert {
display: block;
width:100%;
border: 1px solid #dbdbdb;
-webkit-box-sizing: border-box;
-moz-box-sizing: border-box;
box-sizing: border-box;
}
.insert .file-list {
height: 100px;
overflow: auto;
border: 1px solid #989898;
padding: 10px;
text-align: left;
}
.insert .file-list .filebox p {
font-size: 14px;
/*margin-top: 10px;*/
display: inline-block;
}
.insert .file-list .filebox .delete i{
color: #ff5353;
margin-left: 5px;
}
/** 회의록 [E] **/
/** 파일 BOX [S] **/
span.file-delete{
padding:2px 5px;
margin:5px;
border-radius: 5px;
border:1px solid red;
background: white;
color:red;
}
.appendix{
padding:2px 5px;
margin:5px;
border:1px solid silver;
border-radius: 5px;
background: white;
display: inline-block;
}
/** 파일 BOX [E] **/
/** 좌우정렬 [S] **/
.container_div {
display: flex;
justify-content: space-between;
width: 100%;
}
.left_div {
flex-grow: 1; /* 남는 공간을 모두 차지하도록 설정 */
display: flex; /* Flexbox 사용 */
justify-content: left; /* 가로 중앙 정렬 */
align-items: center; /* 세로 중앙 정렬 */
}
.right_div {
width: 80px; /* 고정 너비 설정 */
display: flex; /* Flexbox 사용 */
justify-content: right; /* 가로 중앙 정렬 */
align-items: center; /* 세로 중앙 정렬 */
}
/** 좌우정렬 [E] **/
/** 진행업무 리스트 [S] **/
.site_01{
color:blue;
}
.site_10{
color:red;
}
/** 진행업무 리스트 [E] **/
/** 달력(스케쥴) [S] **/
div.cal_box{
display: inline-block;
padding: 2px 5px;
border-radius: 5px;
border: 1px solid #d0d0d0;
margin-top: 5px;
width: 100%;
max-width: 160px;
text-align: left;
background: white;
z-index: 10;
}
span.cal_box{
margin:5px;
padding: 3px 0px;
border-radius: 5px;
border: 1px solid #d0d0d0;
text-align: left;
background: white;
}
.cal_today{
background: #f1f1f1 !important;
}
.cal_td{
vertical-align: top !important;
height: 80px;
text-align: left !important;
}
.schedule>tbody>tr>td:first-child{
background: #fff3f3;
}
.schedule>tbody>tr>td:last-child{
background: #f3f3ff;
}
.cal_td > div:first-child{
text-align: right;
}
/* 숫자 기본 표시 */
.schedule-btn-add .day-num {
display: inline-block;
background-color: transparent; /* 배경색 없음 */
border: none; /* 테두리 없음 */
}
/* plus-btn은 초기에는 숨깁니다. */
.schedule-btn-add .plus-btn {
display: none;
cursor: pointer;
}
/* 마우스를 요소 위로 올릴 때 plus-btn을 보이게 합니다. */
.schedule-btn-add:hover .day-num {
display: none;
}
.schedule-btn-add:hover .plus-btn {
display: inline-block;
}
.day {
position: relative;
width: 100%;
height:100%;
overflow: hidden;
}
.day::before {
content: attr(data-date);
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
font-size: 40px;
color: rgba(0, 0, 0, 0.1); /* 연한 색상으로 설정 */
z-index: 0;
}
/** 달력(스케쥴) [E] **/
/* 모달 스타일 */
.modal {
display: none;
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
background-color: rgba(0, 0, 0, 0.5);
z-index: 9999;
}
.modal-content {
background-color: #fff;
border-radius: 5px;
padding: 20px;
width: 300px;
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
}
.modal-header {
margin-top: -20px;
padding: 0px 40px 0px 0px; /* X 버튼 공간 확보 */
}
.modal-form {
padding: 0px; /* X 버튼 공간 확보 */
}
/* 하단 버튼 영역 스타일 */
.modal-footer {
padding: 15px 00px; /* 상하좌우 패딩 조정 */
text-align: center;
}
.footer-close-button:hover,
.footer-close-button:focus {
color: black;
text-decoration: underline;
}
/* 닫기 버튼 스타일 */
.close-button {
color: #aaa;
font-size: 24px;
font-weight: bold;
cursor: pointer;
}
.close-button:hover,
.close-button:focus {
color: black;
text-decoration: none;
}
.close-button {
position: absolute;
top: 10px;
right: 10px;
color: #aaa;
font-size: 24px;
font-weight: bold;
cursor: pointer;
}
.close-button:hover,
.close-button:focus {
color: black;
text-decoration: none;
}
/* 업체정보 스타일 */
.company-user-td {
border:0px solid white !important;
text-align: center;
}
.company-user-td > button {
margin-bottom: 5px;
line-height:15px;
padding: 0px 10px;
}

1338
public/admin/css/font-awesome.css vendored Normal file

File diff suppressed because it is too large Load Diff

4
public/admin/css/font-awesome.min.css vendored Normal file

File diff suppressed because one or more lines are too long

986
public/admin/css/jquery-ui-1.10.3.css vendored Normal file
View File

@@ -0,0 +1,986 @@
/*! jQuery UI - v1.10.3 - 2013-11-20
* http://jqueryui.com
* Includes: jquery.ui.core.css, jquery.ui.resizable.css, jquery.ui.selectable.css, jquery.ui.accordion.css, jquery.ui.autocomplete.css, jquery.ui.button.css, jquery.ui.datepicker.css, jquery.ui.dialog.css, jquery.ui.menu.css, jquery.ui.progressbar.css, jquery.ui.slider.css, jquery.ui.spinner.css, jquery.ui.tabs.css, jquery.ui.tooltip.css
* Copyright 2013 jQuery Foundation and other contributors; Licensed MIT */
/* Layout helpers
----------------------------------*/
.ui-helper-hidden {
display: none;
}
.ui-helper-hidden-accessible {
border: 0;
clip: rect(0 0 0 0);
height: 1px;
margin: -1px;
overflow: hidden;
padding: 0;
position: absolute;
width: 1px;
}
.ui-helper-reset {
margin: 0;
padding: 0;
border: 0;
outline: 0;
line-height: 1.3;
text-decoration: none;
font-size: 100%;
list-style: none;
}
.ui-helper-clearfix:before,
.ui-helper-clearfix:after {
content: "";
display: table;
border-collapse: collapse;
}
.ui-helper-clearfix:after {
clear: both;
}
.ui-helper-clearfix {
min-height: 0; /* support: IE7 */
}
.ui-helper-zfix {
width: 100%;
height: 100%;
top: 0;
left: 0;
position: absolute;
opacity: 0;
filter:Alpha(Opacity=0);
}
.ui-front {
z-index: 100;
}
/* Interaction Cues
----------------------------------*/
.ui-state-disabled {
cursor: default !important;
}
/* Icons
----------------------------------*/
/* states and images */
.ui-icon {
display: block;
text-indent: -99999px;
overflow: hidden;
background-repeat: no-repeat;
}
/* Misc visuals
----------------------------------*/
/* Overlays */
.ui-widget-overlay {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
}
.ui-resizable {
position: relative;
}
.ui-resizable-handle {
position: absolute;
font-size: 0.1px;
display: block;
}
.ui-resizable-disabled .ui-resizable-handle,
.ui-resizable-autohide .ui-resizable-handle {
display: none;
}
.ui-resizable-n {
cursor: n-resize;
height: 7px;
width: 100%;
top: -5px;
left: 0;
}
.ui-resizable-s {
cursor: s-resize;
height: 7px;
width: 100%;
bottom: -5px;
left: 0;
}
.ui-resizable-e {
cursor: e-resize;
width: 7px;
right: -5px;
top: 0;
height: 100%;
}
.ui-resizable-w {
cursor: w-resize;
width: 7px;
left: -5px;
top: 0;
height: 100%;
}
.ui-resizable-se {
cursor: se-resize;
width: 12px;
height: 12px;
right: 1px;
bottom: 1px;
}
.ui-resizable-sw {
cursor: sw-resize;
width: 9px;
height: 9px;
left: -5px;
bottom: -5px;
}
.ui-resizable-nw {
cursor: nw-resize;
width: 9px;
height: 9px;
left: -5px;
top: -5px;
}
.ui-resizable-ne {
cursor: ne-resize;
width: 9px;
height: 9px;
right: -5px;
top: -5px;
}
.ui-selectable-helper {
position: absolute;
z-index: 100;
border: 1px dotted black;
}
.ui-accordion .ui-accordion-header {
display: block;
cursor: pointer;
position: relative;
margin-top: 2px;
padding: .5em .5em .5em .7em;
min-height: 0; /* support: IE7 */
}
.ui-accordion .ui-accordion-icons {
padding-left: 2.2em;
}
.ui-accordion .ui-accordion-noicons {
padding-left: .7em;
}
.ui-accordion .ui-accordion-icons .ui-accordion-icons {
padding-left: 2.2em;
}
.ui-accordion .ui-accordion-header .ui-accordion-header-icon {
position: absolute;
left: .5em;
top: 50%;
margin-top: -8px;
}
.ui-accordion .ui-accordion-content {
padding: 1em 2.2em;
border-top: 0;
overflow: auto;
}
.ui-autocomplete {
position: absolute;
top: 0;
left: 0;
cursor: default;
}
.ui-button {
display: inline-block;
position: relative;
padding: 0;
line-height: normal;
margin-right: .1em;
cursor: pointer;
vertical-align: middle;
text-align: center;
overflow: visible; /* removes extra width in IE */
}
.ui-button,
.ui-button:link,
.ui-button:visited,
.ui-button:hover,
.ui-button:active {
text-decoration: none;
}
/* to make room for the icon, a width needs to be set here */
.ui-button-icon-only {
width: 2.2em;
}
/* button elements seem to need a little more width */
button.ui-button-icon-only {
width: 2.4em;
}
.ui-button-icons-only {
width: 3.4em;
}
button.ui-button-icons-only {
width: 3.7em;
}
/* button text element */
.ui-button .ui-button-text {
display: block;
line-height: normal;
}
.ui-button-text-only .ui-button-text {
padding: .4em 1em;
}
.ui-button-icon-only .ui-button-text,
.ui-button-icons-only .ui-button-text {
padding: .4em;
text-indent: -9999999px;
}
.ui-button-text-icon-primary .ui-button-text,
.ui-button-text-icons .ui-button-text {
padding: .4em 1em .4em 2.1em;
}
.ui-button-text-icon-secondary .ui-button-text,
.ui-button-text-icons .ui-button-text {
padding: .4em 2.1em .4em 1em;
}
.ui-button-text-icons .ui-button-text {
padding-left: 2.1em;
padding-right: 2.1em;
}
/* no icon support for input elements, provide padding by default */
input.ui-button {
padding: .4em 1em;
}
/* button icon element(s) */
.ui-button-icon-only .ui-icon,
.ui-button-text-icon-primary .ui-icon,
.ui-button-text-icon-secondary .ui-icon,
.ui-button-text-icons .ui-icon,
.ui-button-icons-only .ui-icon {
position: absolute;
top: 50%;
margin-top: -8px;
}
.ui-button-icon-only .ui-icon {
left: 50%;
margin-left: -8px;
}
.ui-button-text-icon-primary .ui-button-icon-primary,
.ui-button-text-icons .ui-button-icon-primary,
.ui-button-icons-only .ui-button-icon-primary {
left: .5em;
}
.ui-button-text-icon-secondary .ui-button-icon-secondary,
.ui-button-text-icons .ui-button-icon-secondary,
.ui-button-icons-only .ui-button-icon-secondary {
right: .5em;
}
/* button sets */
.ui-buttonset {
margin-right: 7px;
}
.ui-buttonset .ui-button {
margin-left: 0;
margin-right: -.3em;
}
/* workarounds */
/* reset extra padding in Firefox, see h5bp.com/l */
input.ui-button::-moz-focus-inner,
button.ui-button::-moz-focus-inner {
border: 0;
padding: 0;
}
.ui-datepicker {
width: 17em;
padding: .2em .2em 0;
display: none;
}
.ui-datepicker .ui-datepicker-header {
position: relative;
padding: .2em 0;
}
.ui-datepicker .ui-datepicker-prev,
.ui-datepicker .ui-datepicker-next {
position: absolute;
top: 2px;
width: 1.8em;
height: 1.8em;
}
.ui-datepicker .ui-datepicker-prev-hover,
.ui-datepicker .ui-datepicker-next-hover {
top: 1px;
}
.ui-datepicker .ui-datepicker-prev {
left: 2px;
}
.ui-datepicker .ui-datepicker-next {
right: 2px;
}
.ui-datepicker .ui-datepicker-prev-hover {
left: 1px;
}
.ui-datepicker .ui-datepicker-next-hover {
right: 1px;
}
.ui-datepicker .ui-datepicker-prev span,
.ui-datepicker .ui-datepicker-next span {
display: block;
position: absolute;
left: 50%;
margin-left: -8px;
top: 50%;
margin-top: -8px;
}
.ui-datepicker .ui-datepicker-title {
margin: 0 2.3em;
line-height: 1.8em;
text-align: center;
}
.ui-datepicker .ui-datepicker-title select {
font-size: 1em;
margin: 1px 0;
}
.ui-datepicker select.ui-datepicker-month-year {
width: 100%;
}
.ui-datepicker select.ui-datepicker-month,
.ui-datepicker select.ui-datepicker-year {
width: 49%;
}
.ui-datepicker table {
width: 100%;
font-size: .9em;
border-collapse: collapse;
margin: 0 0 .4em;
}
.ui-datepicker th {
padding: .7em .3em;
text-align: center;
font-weight: bold;
border: 0;
}
.ui-datepicker td {
border: 0;
padding: 1px;
}
.ui-datepicker td span,
.ui-datepicker td a {
display: block;
padding: .2em;
text-align: right;
text-decoration: none;
}
.ui-datepicker .ui-datepicker-buttonpane {
background-image: none;
margin: .7em 0 0 0;
padding: 0 .2em;
border-left: 0;
border-right: 0;
border-bottom: 0;
}
.ui-datepicker .ui-datepicker-buttonpane button {
float: right;
margin: .5em .2em .4em;
cursor: pointer;
padding: .2em .6em .3em .6em;
width: auto;
overflow: visible;
}
.ui-datepicker .ui-datepicker-buttonpane button.ui-datepicker-current {
float: left;
}
/* with multiple calendars */
.ui-datepicker.ui-datepicker-multi {
width: auto;
}
.ui-datepicker-multi .ui-datepicker-group {
float: left;
}
.ui-datepicker-multi .ui-datepicker-group table {
width: 95%;
margin: 0 auto .4em;
}
.ui-datepicker-multi-2 .ui-datepicker-group {
width: 50%;
}
.ui-datepicker-multi-3 .ui-datepicker-group {
width: 33.3%;
}
.ui-datepicker-multi-4 .ui-datepicker-group {
width: 25%;
}
.ui-datepicker-multi .ui-datepicker-group-last .ui-datepicker-header,
.ui-datepicker-multi .ui-datepicker-group-middle .ui-datepicker-header {
border-left-width: 0;
}
.ui-datepicker-multi .ui-datepicker-buttonpane {
clear: left;
}
.ui-datepicker-row-break {
clear: both;
width: 100%;
font-size: 0;
}
/* RTL support */
.ui-datepicker-rtl {
direction: rtl;
}
.ui-datepicker-rtl .ui-datepicker-prev {
right: 2px;
left: auto;
}
.ui-datepicker-rtl .ui-datepicker-next {
left: 2px;
right: auto;
}
.ui-datepicker-rtl .ui-datepicker-prev:hover {
right: 1px;
left: auto;
}
.ui-datepicker-rtl .ui-datepicker-next:hover {
left: 1px;
right: auto;
}
.ui-datepicker-rtl .ui-datepicker-buttonpane {
clear: right;
}
.ui-datepicker-rtl .ui-datepicker-buttonpane button {
float: left;
}
.ui-datepicker-rtl .ui-datepicker-buttonpane button.ui-datepicker-current,
.ui-datepicker-rtl .ui-datepicker-group {
float: right;
}
.ui-datepicker-rtl .ui-datepicker-group-last .ui-datepicker-header,
.ui-datepicker-rtl .ui-datepicker-group-middle .ui-datepicker-header {
border-right-width: 0;
border-left-width: 1px;
}
.ui-dialog {
position: absolute;
top: 0;
left: 0;
padding: .2em;
outline: 0;
}
.ui-dialog .ui-dialog-titlebar {
padding: .4em 1em;
position: relative;
}
.ui-dialog .ui-dialog-title {
float: left;
margin: .1em 0;
white-space: nowrap;
width: 90%;
overflow: hidden;
text-overflow: ellipsis;
}
.ui-dialog .ui-dialog-titlebar-close {
position: absolute;
right: .3em;
top: 50%;
width: 21px;
margin: -10px 0 0 0;
padding: 1px;
height: 20px;
}
.ui-dialog .ui-dialog-content {
position: relative;
border: 0;
padding: .5em 1em;
background: none;
overflow: auto;
}
.ui-dialog .ui-dialog-buttonpane {
text-align: left;
border-width: 1px 0 0 0;
background-image: none;
margin-top: .5em;
padding: .3em 1em .5em .4em;
}
.ui-dialog .ui-dialog-buttonpane .ui-dialog-buttonset {
float: right;
}
.ui-dialog .ui-dialog-buttonpane button {
margin: .5em .4em .5em 0;
cursor: pointer;
}
.ui-dialog .ui-resizable-se {
width: 12px;
height: 12px;
right: -5px;
bottom: -5px;
background-position: 16px 16px;
}
.ui-draggable .ui-dialog-titlebar {
cursor: move;
}
.ui-menu {
list-style: none;
padding: 2px;
margin: 0;
display: block;
outline: none;
}
.ui-menu .ui-menu {
margin-top: -3px;
position: absolute;
}
.ui-menu .ui-menu-item {
margin: 0;
padding: 0;
width: 100%;
/* support: IE10, see #8844 */
list-style-image: url(data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7);
}
.ui-menu .ui-menu-divider {
margin: 5px -2px 5px -2px;
height: 0;
font-size: 0;
line-height: 0;
border-width: 1px 0 0 0;
}
.ui-menu .ui-menu-item a {
text-decoration: none;
display: block;
padding: 2px .4em;
line-height: 1.5;
min-height: 0; /* support: IE7 */
font-weight: normal;
}
.ui-menu .ui-menu-item a.ui-state-focus,
.ui-menu .ui-menu-item a.ui-state-active {
font-weight: normal;
margin: -1px;
}
.ui-menu .ui-state-disabled {
font-weight: normal;
margin: .4em 0 .2em;
line-height: 1.5;
}
.ui-menu .ui-state-disabled a {
cursor: default;
}
/* icon support */
.ui-menu-icons {
position: relative;
}
.ui-menu-icons .ui-menu-item a {
position: relative;
padding-left: 2em;
}
/* left-aligned */
.ui-menu .ui-icon {
position: absolute;
top: .2em;
left: .2em;
}
/* right-aligned */
.ui-menu .ui-menu-icon {
position: static;
float: right;
}
.ui-progressbar {
height: 2em;
text-align: left;
overflow: hidden;
}
.ui-progressbar .ui-progressbar-value {
margin: -1px;
height: 100%;
}
.ui-progressbar .ui-progressbar-overlay {
background: url("images/animated-overlay.gif");
height: 100%;
filter: alpha(opacity=25);
opacity: 0.25;
}
.ui-progressbar-indeterminate .ui-progressbar-value {
background-image: none;
}
.ui-slider {
position: relative;
text-align: left;
}
.ui-slider .ui-slider-handle {
position: absolute;
z-index: 2;
width: 1.2em;
height: 1.2em;
cursor: default;
}
.ui-slider .ui-slider-range {
position: absolute;
z-index: 1;
font-size: .7em;
display: block;
border: 0;
background-position: 0 0;
}
/* For IE8 - See #6727 */
.ui-slider.ui-state-disabled .ui-slider-handle,
.ui-slider.ui-state-disabled .ui-slider-range {
filter: inherit;
}
.ui-slider-horizontal {
height: .8em;
}
.ui-slider-horizontal .ui-slider-handle {
top: -.3em;
margin-left: -.6em;
}
.ui-slider-horizontal .ui-slider-range {
top: 0;
height: 100%;
}
.ui-slider-horizontal .ui-slider-range-min {
left: 0;
}
.ui-slider-horizontal .ui-slider-range-max {
right: 0;
}
.ui-slider-vertical {
width: .8em;
height: 100px;
}
.ui-slider-vertical .ui-slider-handle {
left: -.3em;
margin-left: 0;
margin-bottom: -.6em;
}
.ui-slider-vertical .ui-slider-range {
left: 0;
width: 100%;
}
.ui-slider-vertical .ui-slider-range-min {
bottom: 0;
}
.ui-slider-vertical .ui-slider-range-max {
top: 0;
}
.ui-spinner {
position: relative;
display: inline-block;
overflow: hidden;
padding: 0;
vertical-align: middle;
}
.ui-spinner-input {
border: none;
background: none;
color: inherit;
padding: 0;
margin: .2em 0;
vertical-align: middle;
margin-left: .4em;
margin-right: 22px;
}
.ui-spinner-button {
width: 16px;
height: 50%;
font-size: .5em;
padding: 0;
margin: 0;
text-align: center;
position: absolute;
cursor: default;
display: block;
overflow: hidden;
right: 0;
}
/* more specificity required here to overide default borders */
.ui-spinner a.ui-spinner-button {
border-top: none;
border-bottom: none;
border-right: none;
}
/* vertical centre icon */
.ui-spinner .ui-icon {
position: absolute;
margin-top: -8px;
top: 50%;
left: 0;
}
.ui-spinner-up {
top: 0;
}
.ui-spinner-down {
bottom: 0;
}
/* TR overrides */
.ui-spinner .ui-icon-triangle-1-s {
/* need to fix icons sprite */
background-position: -65px -16px;
}
.ui-tabs {
position: relative;/* position: relative prevents IE scroll bug (element with position: relative inside container with overflow: auto appear as "fixed") */
padding: .2em;
}
.ui-tabs .ui-tabs-nav {
margin: 0;
padding: .2em .2em 0;
}
.ui-tabs .ui-tabs-nav li {
list-style: none;
float: left;
position: relative;
top: 0;
margin: 1px .2em 0 0;
border-bottom-width: 0;
padding: 0;
white-space: nowrap;
}
.ui-tabs .ui-tabs-nav li a {
float: left;
padding: .5em 1em;
text-decoration: none;
}
.ui-tabs .ui-tabs-nav li.ui-tabs-active {
margin-bottom: -1px;
padding-bottom: 1px;
}
.ui-tabs .ui-tabs-nav li.ui-tabs-active a,
.ui-tabs .ui-tabs-nav li.ui-state-disabled a,
.ui-tabs .ui-tabs-nav li.ui-tabs-loading a {
cursor: text;
}
.ui-tabs .ui-tabs-nav li a, /* first selector in group seems obsolete, but required to overcome bug in Opera applying cursor: text overall if defined elsewhere... */
.ui-tabs-collapsible .ui-tabs-nav li.ui-tabs-active a {
cursor: pointer;
}
.ui-tabs .ui-tabs-panel {
display: block;
border-width: 0;
padding: 1em 1.4em;
background: none;
}
.ui-tooltip {
padding: 8px;
position: absolute;
z-index: 9999;
max-width: 300px;
-webkit-box-shadow: 0 0 5px #aaa;
box-shadow: 0 0 5px #aaa;
}
body .ui-tooltip {
border-width: 2px;
}
/* JQUERY UI THEME */
.ui-datepicker {
background: #1D2939;
margin-top: 1px;
z-index: 100000;
-moz-border-radius: 2px;
-webkit-border-radius: 2px;
border-radius: 2px;
width: 280px;
}
.ui-datepicker-title {
text-transform: uppercase;
font-family: 'LatoBold';
color: #1CAF9A;
}
.ui-datepicker th {
text-transform: uppercase;
font-family: 'LatoBold';
font-weight: normal;
font-size: 11px;
color: #fff;
}
.ui-datepicker td.ui-datepicker-today a {
background: rgba(255,255,255,0.1);
}
.ui-datepicker td a {
color: #636E7B;
-moz-border-radius: 2px;
-webkit-border-radius: 2px;
border-radius: 2px;
padding: 3px 5px;
-moz-transition: all 0.2s ease-out 0s;
-webkit-transition: all 0.2s ease-out 0s;
transition: all 0.2s ease-out 0s;
}
.ui-datepicker td a:hover {
background: #1CAF9A;
color: #fff;
}
.ui-datepicker-next,
.ui-datepicker-prev {
-moz-transition: all 0.2s ease-out 0s;
-webkit-transition: all 0.2s ease-out 0s;
transition: all 0.2s ease-out 0s;
-moz-border-radius: 2px;
-webkit-border-radius: 2px;
border-radius: 2px;
}
.ui-datepicker-next {
background: url(../images/calendar-arrow.png) no-repeat 10px 5px;
}
.ui-datepicker-next:hover {
top: 2px;
right: 2px;
background-color: #1CAF9A;
cursor: pointer;
}
.ui-datepicker-prev {
background: url(../images/calendar-arrow.png) no-repeat 8px -80px;
}
.ui-datepicker-prev:hover {
top: 2px;
left: 2px;
background-color: #1CAF9A;
cursor: pointer;
}
.ui-datepicker-buttonpane button {
border: 0;
background: #1CAF9A;
color: #fff;
-moz-border-radius: 2px;
-webkit-border-radius: 2px;
border-radius: 2px;
padding: 7px 10px;
}
.ui-spinner {
border: 1px solid #ccc;
background: #fff;
-moz-border-radius: 2px;
-webkit-border-radius: 2px;
border-radius: 2px;
overflow: hidden;
}
.ui-spinner-input {
margin: 0 20px 0 0;
padding: 10px;
}
.ui-spinner-button {
background-color: #E4E7EA;
border-left: 1px solid #ccc;
width: 32px;
background-repeat: no-repeat;
background-image: url(../images/dropdown-arrow.png);
cursor: pointer;
}
.ui-spinner-up {
background-position: 9px -41px;
border-bottom: 1px solid #ccc !important;
}
.ui-spinner-down {
background-position: 9px 6px;
}
.ui-spinner-button:hover {
background-color: #f3f3f3;
}
.ui-slider {
background: rgba(17,18,18,0.1);
-moz-border-radius: 3px;
-webkit-border-radius: 3px;
border-radius: 3px;
}
.ui-slider-horizontal {
height: 6px;
margin: 15px 0;
}
.ui-slider .ui-slider-handle {
background: #999;
border: 6px solid #fff;
width: 20px;
height: 20px;
-moz-border-radius: 50px;
-webkit-border-radius: 50px;
border-radius: 50px;
top: -0.4em;
cursor: pointer;
-moz-box-shadow: 0 0 2px rgba(0,0,0,0.4);
-webkit-box-shadow: 0 0 2px rgba(0,0,0,0.4);
box-shadow: 0 0 2px rgba(0,0,0,0.4);
}
.ui-slider .ui-slider-handle:hover {
-moz-box-shadow: 0 0 6px rgba(0,0,0,0.5);
-webkit-box-shadow: 0 0 6px rgba(0,0,0,0.5);
box-shadow: 0 0 6px rgba(0,0,0,0.5);
}
.ui-slider .ui-slider-range {
-moz-border-radius: 3px;
-webkit-border-radius: 3px;
border-radius: 3px;
background: #999;
}
.slider-primary .ui-slider-range,
.slider-primary .ui-slider-handle {
background-color: #428BCA;
}
.slider-success .ui-slider-range,
.slider-success .ui-slider-handle {
background-color: #1CAF9A;
}
.slider-warning .ui-slider-range,
.slider-warning .ui-slider-handle {
background-color: #F0AD4E;
}
.slider-danger .ui-slider-range,
.slider-danger .ui-slider-handle {
background-color: #D9534F;
}
.slider-info .ui-slider-range,
.slider-info .ui-slider-handle {
background-color: #5BC0DE;
}
.ui-slider-vertical {
width: 6px;
display: inline-block;
}
.ui-slider-vertical .ui-slider-handle {
top: auto;
left: -7px;
}

View File

@@ -0,0 +1,253 @@
.dataTables_wrapper {
position: relative;
clear: both;
*zoom: 1;
}
.dataTables_length {
float: left;
margin-bottom: 10px;
}
.dataTables_length::after {
clear: both;
display: block;
content: '';
}
.dataTables_length label {
display: inline-block;
}
.dataTable {
display: inline-table;
}
.dataTable:before {
display: block;
clear: both;
content: '';
}
.dataTable thead > tr > th {
background-color: transparent;
background-repeat: no-repeat;
background-position: 97% center;
}
.dataTables_filter {
float: right;
text-align: right;
margin-bottom: 10px;
}
.dataTables_filter:after {
display: block;
clear: both;
content: '';
}
.dataTables_filter input {
border: 1px solid #ddd;
padding: 10px;
font-zize: 13px;
-moz-border-radius: 3px;
-webkit-border-radius: 3px;
border-radius: 3px;
margin-left: 5px;
}
.dataTables_filter input:focus {
border-color: #999;
-moz-box-shadow: 3px 3px 0 rgba(0,0,0,0.05);
-webkit-box-shadow: 3px 3px 0 rgba(0,0,0,0.05);
box-shadow: 3px 3px 0 rgba(0,0,0,0.05);
}
.dataTables_info {
clear: both;
float: left;
}
.dataTables_paginate {
float: right;
text-align: right;
}
/* Two button pagination - previous / next */
.paginate_disabled_previous,
.paginate_enabled_previous,
.paginate_disabled_next,
.paginate_enabled_next {
float: left;
cursor: pointer;
padding: 6px 15px;
display: inline-block;
-moz-border-radius: 3px;
-webkit-border-radius: 3px;
border-radius: 3px;
color: #666;
}
.paginate_enabled_previous,
.paginate_enabled_next {
color: #fff;
background: #428BCA;
border: 1px solid #357EBD;
}
.paginate_enabled_previous:hover,
.paginate_enabled_next:hover {
color: #fff;
background: #3276B1;
border-color: #285E8E;
color: #fff;
text-decoration: none;
}
.paginate_disabled_previous,
.paginate_disabled_next {
border: 1px solid #ccc;
background-color: #ddd;
color: #999;
}
.paginate_disabled_previous:hover,
.paginate_disabled_next:hover {
text-decoration: none;
color: #999;
cursor: default;
}
.paginate_disabled_next,
.paginate_enabled_next {
margin-left: 5px;
}
/* Full number pagination */
.paging_full_numbers {
line-height: 22px;
}
.paging_full_numbers a:active {
outline: none
}
.paging_full_numbers a:hover {
text-decoration: none;
}
.paging_full_numbers a.paginate_button,
.paging_full_numbers a.paginate_active {
border: 1px solid #ddd;
padding: 6px 12px;
margin-right: 5px;
cursor: pointer;
color: #636E7B;
line-height: 21px;
float: left;
position: relative;
background: #fff;
display: inline-block;
-moz-border-radius: 3px;
-webkit-border-radius: 3px;
border-radius: 3px;
}
.paging_full_numbers > li:first-child > a,
.paging_full_numbers > li:first-child > span {
border-bottom-left-radius: 3px;
border-top-left-radius: 3px;
}
.paging_full_numbers a.paginate_button:hover {
text-decoration: none !important;
background-color: #E4E7EA;
}
.paging_full_numbers a.paginate_active {
background-color: #1CAF9A;
border-color: #1CAF9A;
color: #fff;
}
.paging_full_numbers a:focus {
text-decoration: none;
}
.paging_full_numbers a.last {
margin-right: 0;
}
.paginate_button_disabled {
opacity: 0.5;
}
.paginate_button_disabled:hover {
cursor: default !important;
background-color: #fff !important;
}
/*
* Processing indicator
*/
.dataTables_processing {
position: absolute;
top: 50%;
left: 50%;
width: 250px;
height: 30px;
margin-left: -125px;
margin-top: -15px;
padding: 14px 0 2px 0;
border: 1px solid #ddd;
text-align: center;
color: #999;
font-size: 14px;
background-color: white;
}
/*
* Sorting
*/
.sorting {
background-image: url('../images/sort_both.png');
}
.sorting_asc {
background-image: url('../images/sort_asc.png');
}
.sorting_desc {
background-image: url('../images/sort_desc.png');
}
.sorting_asc_disabled {
background-image: url('../images/sort_asc_disabled.png');
}
.sorting_desc_disabled {
background-image: url('../images/sort_desc_disabled.png');
}
table.dataTable thead th:active,
table.dataTable thead td:active {
outline: none;
}
/*
* Scrolling
*/
.dataTables_scroll {
clear: both;
}
.dataTables_scrollBody {
*margin-top: -1px;
-webkit-overflow-scrolling: touch;
}

124
public/admin/css/lato.css Normal file
View File

@@ -0,0 +1,124 @@
/* Generated by Font Squirrel (http://www.fontsquirrel.com) on January 26, 2013 07:16:15 AM America/New_York */
@font-face {
font-family: 'LatoBlackItalic';
src: url('../fonts/lato/Lato-BlaIta-webfont.eot');
src: url('../fonts/lato/Lato-BlaIta-webfont.eot?#iefix') format('embedded-opentype'),
url('../fonts/lato/Lato-BlaIta-webfont.woff') format('woff'),
url('../fonts/lato/Lato-BlaIta-webfont.ttf') format('truetype'),
url('../fonts/lato/Lato-BlaIta-webfont.svg#LatoBlackItalic') format('svg');
font-weight: normal;
font-style: normal;
}
@font-face {
font-family: 'LatoBlack';
src: url('../fonts/lato/Lato-Bla-webfont.eot');
src: url('../fonts/lato/Lato-Bla-webfont.eot?#iefix') format('embedded-opentype'),
url('../fonts/lato/Lato-Bla-webfont.woff') format('woff'),
url('../fonts/lato/Lato-Bla-webfont.ttf') format('truetype'),
url('../fonts/lato/Lato-Bla-webfont.svg#LatoBlack') format('svg');
font-weight: normal;
font-style: normal;
}
@font-face {
font-family: 'LatoBoldItalic';
src: url('../fonts/lato/Lato-BolIta-webfont.eot');
src: url('../fonts/lato/Lato-BolIta-webfont.eot?#iefix') format('embedded-opentype'),
url('../fonts/lato/Lato-BolIta-webfont.woff') format('woff'),
url('../fonts/lato/Lato-BolIta-webfont.ttf') format('truetype'),
url('../fonts/lato/Lato-BolIta-webfont.svg#LatoBoldItalic') format('svg');
font-weight: normal;
font-style: normal;
}
@font-face {
font-family: 'LatoBold';
src: url('../fonts/lato/Lato-Bol-webfont.eot');
src: url('../fonts/lato/Lato-Bol-webfont.eot?#iefix') format('embedded-opentype'),
url('../fonts/lato/Lato-Bol-webfont.woff') format('woff'),
url('../fonts/lato/Lato-Bol-webfont.ttf') format('truetype'),
url('../fonts/lato/Lato-Bol-webfont.svg#LatoBold') format('svg');
font-weight: normal;
font-style: normal;
}
@font-face {
font-family: 'LatoItalic';
src: url('../fonts/lato/Lato-RegIta-webfont.eot');
src: url('../fonts/lato/Lato-RegIta-webfont.eot?#iefix') format('embedded-opentype'),
url('../fonts/lato/Lato-RegIta-webfont.woff') format('woff'),
url('../fonts/lato/Lato-RegIta-webfont.ttf') format('truetype'),
url('../fonts/lato/Lato-RegIta-webfont.svg#LatoItalic') format('svg');
font-weight: normal;
font-style: normal;
}
@font-face {
font-family: 'LatoRegular';
src: url('../fonts/lato/Lato-Reg-webfont.eot');
src: url('../fonts/lato/Lato-Reg-webfont.eot?#iefix') format('embedded-opentype'),
url('../fonts/lato/Lato-Reg-webfont.woff') format('woff'),
url('../fonts/lato/Lato-Reg-webfont.ttf') format('truetype'),
url('../fonts/lato/Lato-Reg-webfont.svg#LatoRegular') format('svg');
font-weight: normal;
font-style: normal;
}
@font-face {
font-family: 'LatoLightItalic';
src: url('../fonts/lato/Lato-LigIta-webfont.eot');
src: url('../fonts/lato/Lato-LigIta-webfont.eot?#iefix') format('embedded-opentype'),
url('../fonts/lato/Lato-LigIta-webfont.woff') format('woff'),
url('../fonts/lato/Lato-LigIta-webfont.ttf') format('truetype'),
url('../fonts/lato/Lato-LigIta-webfont.svg#LatoLightItalic') format('svg');
font-weight: normal;
font-style: normal;
}
@font-face {
font-family: 'LatoLight';
src: url('../fonts/lato/Lato-Lig-webfont.eot');
src: url('../fonts/lato/Lato-Lig-webfont.eot?#iefix') format('embedded-opentype'),
url('../fonts/lato/Lato-Lig-webfont.woff') format('woff'),
url('../fonts/lato/Lato-Lig-webfont.ttf') format('truetype'),
url('../fonts/lato/Lato-Lig-webfont.svg#LatoLight') format('svg');
font-weight: normal;
font-style: normal;
}
@font-face {
font-family: 'LatoHairlineItalic';
src: url('../fonts/lato/Lato-HaiIta-webfont.eot');
src: url('../fonts/lato/Lato-HaiIta-webfont.eot?#iefix') format('embedded-opentype'),
url('../fonts/lato/Lato-HaiIta-webfont.woff') format('woff'),
url('../fonts/lato/Lato-HaiIta-webfont.ttf') format('truetype'),
url('../fonts/lato/Lato-HaiIta-webfont.svg#LatoHairlineItalic') format('svg');
font-weight: normal;
font-style: normal;
}
@font-face {
font-family: 'LatoHairline';
src: url('../fonts/lato/Lato-Hai-webfont.eot');
src: url('../fonts/lato/Lato-Hai-webfont.eot?#iefix') format('embedded-opentype'),
url('../fonts/lato/Lato-Hai-webfont.woff') format('woff'),
url('../fonts/lato/Lato-Hai-webfont.ttf') format('truetype'),
url('../fonts/lato/Lato-Hai-webfont.svg#LatoHairline') format('svg');
font-weight: normal;
font-style: normal;
}

117
public/admin/css/layout.css Normal file
View File

@@ -0,0 +1,117 @@
/* layout_css */
/* member */
.call {
padding-top: 0px;
width: 144px;
text-align: center;
height: 32px;
float:left;
}
.space-in{
margin-left: 8px;
margin-right: 8px;
padding-top: 8px;
}
.radio_check, .radio, .checkbox{
float:left;
}
.radio, .checkbox{
margin-left: 5px;
}
.f_raido{
margin-left:26px;
margin-right:22px;
}
.f_check{
margin-left:10px;
}
.databox{
padding: 7px;
}
.btn{
margin-left:10px;
}
.member_table{
/*margin-top:30px;*/
margin-top:10px;
text-align: center;
}
.member_table thead > tr > th{
background-color: #ddd;
font-weight:bold;
}
.m_pager{
text-align:center;
}
.member_table thead tr > th, .member_table thead tr > td, .member_table tbody tr > th, .member_table tbody tr > td, .member_table tfoot tr > th, .member_table tfoot tr > td {
border: 1px solid #CCC5B9;
text-align: center;
vertical-align: middle;
display: table-cell;
WORD-BREAK:break-all;
}
.member_table2{
margin-top:5px;
text-align: center;
}
.member_table2 thead > tr > th{
background-color: #ddd;
font-weight:bold;
}
.member_table2 thead tr > th, .member_table2 thead tr > td, .member_table2 tbody tr > th, .member_table2 tbody tr > td, .member_table2 tfoot tr > th, .member_table2 tfoot tr > td {
border: 1px solid #CCC5B9;
text-align: center;
vertical-align: middle;
display: table-cell;
WORD-BREAK:break-all;
}
.event_table thead tr > th, .event_table thead tr > td, .event_table tbody tr > th, .event_table tbody tr > td, .event_table tfoot tr > th, .event_table tfoot tr > td {
text-align: center;
vertical-align: 50%;
WORD-BREAK:break-all;
}
/* member end */
/*board*/
.toggle-toggle {
padding-left:25%;
}
.hide {display:none;}
.item td {cursor:pointer;}
.show_tb {display:table-row;}
/*board end*/
/*event-push*/
.img-box img {width:50%; height:auto;}
/*event-push*/
/*contextMenu*/
.member-id {cursor:pointer; color:#5995c8; }
.company-id {cursor:pointer; color: #595bc8; font-weight: bold;}
.contextMenu-sms {border-top:1px solid #ddd;}
.info-p{line-height:2.5px;}

192
public/admin/css/roboto.css Normal file
View File

@@ -0,0 +1,192 @@
@font-face {
font-family: 'RobotoRegular';
src: url('../fonts/roboto/Roboto-Regular-webfont.eot');
src: url('../fonts/roboto/Roboto-Regular-webfont.eot?#iefix') format('embedded-opentype'),
url('../fonts/roboto/Roboto-Regular-webfont.woff') format('woff'),
url('../fonts/roboto/Roboto-Regular-webfont.ttf') format('truetype'),
url('../fonts/roboto/Roboto-Regular-webfont.svg#RobotoRegular') format('svg');
font-weight: normal;
font-style: normal;
}
@font-face {
font-family: 'RobotoItalic';
src: url('../fonts/roboto/Roboto-Italic-webfont.eot');
src: url('../fonts/roboto/Roboto-Italic-webfont.eot?#iefix') format('embedded-opentype'),
url('../fonts/roboto/Roboto-Italic-webfont.woff') format('woff'),
url('../fonts/roboto/Roboto-Italic-webfont.ttf') format('truetype'),
url('../fonts/roboto/Roboto-Italic-webfont.svg#RobotoItalic') format('svg');
font-weight: normal;
font-style: normal;
}
@font-face {
font-family: 'RobotoBold';
src: url('../fonts/roboto/Roboto-Bold-webfont.eot');
src: url('../fonts/roboto/Roboto-Bold-webfont.eot?#iefix') format('embedded-opentype'),
url('../fonts/roboto/Roboto-Bold-webfont.woff') format('woff'),
url('../fonts/roboto/Roboto-Bold-webfont.ttf') format('truetype'),
url('../fonts/roboto/Roboto-Bold-webfont.svg#RobotoBold') format('svg');
font-weight: normal;
font-style: normal;
}
@font-face {
font-family: 'RobotoBoldItalic';
src: url('../fonts/roboto/Roboto-BoldItalic-webfont.eot');
src: url('../fonts/roboto/Roboto-BoldItalic-webfont.eot?#iefix') format('embedded-opentype'),
url('../fonts/roboto/Roboto-BoldItalic-webfont.woff') format('woff'),
url('../fonts/roboto/Roboto-BoldItalic-webfont.ttf') format('truetype'),
url('../fonts/roboto/Roboto-BoldItalic-webfont.svg#RobotoBoldItalic') format('svg');
font-weight: normal;
font-style: normal;
}
@font-face {
font-family: 'RobotoCondensed';
src: url('../fonts/roboto/Roboto-Condensed-webfont.eot');
src: url('../fonts/roboto/Roboto-Condensed-webfont.eot?#iefix') format('embedded-opentype'),
url('../fonts/roboto/Roboto-Condensed-webfont.woff') format('woff'),
url('../fonts/roboto/Roboto-Condensed-webfont.ttf') format('truetype'),
url('../fonts/roboto/Roboto-Condensed-webfont.svg#RobotoCondensed') format('svg');
font-weight: normal;
font-style: normal;
}
@font-face {
font-family: 'RobotoCondensedItalic';
src: url('../fonts/roboto/Roboto-CondensedItalic-webfont.eot');
src: url('../fonts/roboto/Roboto-CondensedItalic-webfont.eot?#iefix') format('embedded-opentype'),
url('../fonts/roboto/Roboto-CondensedItalic-webfont.woff') format('woff'),
url('../fonts/roboto/Roboto-CondensedItalic-webfont.ttf') format('truetype'),
url('../fonts/roboto/Roboto-CondensedItalic-webfont.svg#RobotoCondensedItalic') format('svg');
font-weight: normal;
font-style: normal;
}
@font-face {
font-family: 'RobotoBoldCondensed';
src: url('../fonts/roboto/Roboto-BoldCondensed-webfont.eot');
src: url('../fonts/roboto/Roboto-BoldCondensed-webfont.eot?#iefix') format('embedded-opentype'),
url('../fonts/roboto/Roboto-BoldCondensed-webfont.woff') format('woff'),
url('../fonts/roboto/Roboto-BoldCondensed-webfont.ttf') format('truetype'),
url('../fonts/roboto/Roboto-BoldCondensed-webfont.svg#RobotoBoldCondensed') format('svg');
font-weight: normal;
font-style: normal;
}
@font-face {
font-family: 'RobotoBoldCondensedItalic';
src: url('../fonts/roboto/Roboto-BoldCondensedItalic-webfont.eot');
src: url('../fonts/roboto/Roboto-BoldCondensedItalic-webfont.eot?#iefix') format('embedded-opentype'),
url('../fonts/roboto/Roboto-BoldCondensedItalic-webfont.woff') format('woff'),
url('../fonts/roboto/Roboto-BoldCondensedItalic-webfont.ttf') format('truetype'),
url('../fonts/roboto/Roboto-BoldCondensedItalic-webfont.svg#RobotoBoldCondensedItalic') format('svg');
font-weight: normal;
font-style: normal;
}
@font-face {
font-family: 'RobotoThin';
src: url('../fonts/roboto/Roboto-Thin-webfont.eot');
src: url('../fonts/roboto/Roboto-Thin-webfont.eot?#iefix') format('embedded-opentype'),
url('../fonts/roboto/Roboto-Thin-webfont.woff') format('woff'),
url('../fonts/roboto/Roboto-Thin-webfont.ttf') format('truetype'),
url('../fonts/roboto/Roboto-Thin-webfont.svg#RobotoThin') format('svg');
font-weight: normal;
font-style: normal;
}
@font-face {
font-family: 'RobotoThinItalic';
src: url('../fonts/roboto/Roboto-ThinItalic-webfont.eot');
src: url('../fonts/roboto/Roboto-ThinItalic-webfont.eot?#iefix') format('embedded-opentype'),
url('../fonts/roboto/Roboto-ThinItalic-webfont.woff') format('woff'),
url('../fonts/roboto/Roboto-ThinItalic-webfont.ttf') format('truetype'),
url('../fonts/roboto/Roboto-ThinItalic-webfont.svg#RobotoThinItalic') format('svg');
font-weight: normal;
font-style: normal;
}
@font-face {
font-family: 'RobotoLight';
src: url('../fonts/roboto/Roboto-Light-webfont.eot');
src: url('../fonts/roboto/Roboto-Light-webfont.eot?#iefix') format('embedded-opentype'),
url('../fonts/roboto/Roboto-Light-webfont.woff') format('woff'),
url('../fonts/roboto/Roboto-Light-webfont.ttf') format('truetype'),
url('../fonts/roboto/Roboto-Light-webfont.svg#RobotoLight') format('svg');
font-weight: normal;
font-style: normal;
}
@font-face {
font-family: 'RobotoLightItalic';
src: url('../fonts/roboto/Roboto-LightItalic-webfont.eot');
src: url('../fonts/roboto/Roboto-LightItalic-webfont.eot?#iefix') format('embedded-opentype'),
url('../fonts/roboto/Roboto-LightItalic-webfont.woff') format('woff'),
url('../fonts/roboto/Roboto-LightItalic-webfont.ttf') format('truetype'),
url('../fonts/roboto/Roboto-LightItalic-webfont.svg#RobotoLightItalic') format('svg');
font-weight: normal;
font-style: normal;
}
@font-face {
font-family: 'RobotoMedium';
src: url('../fonts/roboto/Roboto-Medium-webfont.eot');
src: url('../fonts/roboto/Roboto-Medium-webfont.eot?#iefix') format('embedded-opentype'),
url('../fonts/roboto/Roboto-Medium-webfont.woff') format('woff'),
url('../fonts/roboto/Roboto-Medium-webfont.ttf') format('truetype'),
url('../fonts/roboto/Roboto-Medium-webfont.svg#RobotoMedium') format('svg');
font-weight: normal;
font-style: normal;
}
@font-face {
font-family: 'RobotoMediumItalic';
src: url('../fonts/roboto/Roboto-MediumItalic-webfont.eot');
src: url('../fonts/roboto/Roboto-MediumItalic-webfont.eot?#iefix') format('embedded-opentype'),
url('../fonts/roboto/Roboto-MediumItalic-webfont.woff') format('woff'),
url('../fonts/roboto/Roboto-MediumItalic-webfont.ttf') format('truetype'),
url('../fonts/roboto/Roboto-MediumItalic-webfont.svg#RobotoMediumItalic') format('svg');
font-weight: normal;
font-style: normal;
}
@font-face {
font-family: 'RobotoBlack';
src: url('../fonts/roboto/Roboto-Black-webfont.eot');
src: url('../fonts/roboto/Roboto-Black-webfont.eot?#iefix') format('embedded-opentype'),
url('../fonts/roboto/Roboto-Black-webfont.woff') format('woff'),
url('../fonts/roboto/Roboto-Black-webfont.ttf') format('truetype'),
url('../fonts/roboto/Roboto-Black-webfont.svg#RobotoBlack') format('svg');
font-weight: normal;
font-style: normal;
}
@font-face {
font-family: 'RobotoBlackItalic';
src: url('../fonts/roboto/Roboto-BlackItalic-webfont.eot');
src: url('../fonts/roboto/Roboto-BlackItalic-webfont.eot?#iefix') format('embedded-opentype'),
url('../fonts/roboto/Roboto-BlackItalic-webfont.woff') format('woff'),
url('../fonts/roboto/Roboto-BlackItalic-webfont.ttf') format('truetype'),
url('../fonts/roboto/Roboto-BlackItalic-webfont.svg#RobotoBlackItalic') format('svg');
font-weight: normal;
font-style: normal;
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,183 @@
body {
background: #fff;
}
/*** HEADER ***/
.logopanel,
.headerbar {
background: #1d2939;
border-bottom: 1px solid #1d2939;
}
.logopanel h1 {
color: #fff;
}
.headerbar {
border-color: rgba(255,255,255,0.05);
}
.menutoggle {
border-color: rgba(255,255,255,0.05);
color: #fff;
}
.menutoggle:hover {
background: rgba(0,0,0,0.1);
color: #fff;
}
.headerbar .searchform input {
background: none;
border-color: rgba(255,255,255,0.05);
}
.headermenu > li {
border-color: rgba(255,255,255,0.05);
}
.headermenu .tp-icon,
.headermenu .dropdown-toggle {
background: none;
}
.headermenu .tp-icon {
color: rgba(255,255,255,0.5);
}
.headermenu .chat-icon {
border: 0;
}
.headermenu .dropdown-menu {
margin-top: 1px;
}
.headermenu .dropdown-toggle:hover,
.headermenu .dropdown-toggle:focus,
.headermenu .dropdown-toggle:active,
.headermenu .dropdown-toggle.active,
.headermenu .open .dropdown-toggle.dropdown-toggle {
background: rgba(0,0,0,0.1);
color: rgba(255,255,255,0.8);
}
.dropdown-menu-head .title {
background: #fff;
border: 1px solid #ddd;
border-bottom-color: #eee;
border-top: 0;
}
.headermenu .dropdown-menu:after {
border-bottom-color: #fff;
}
.headermenu .dropdown-menu-usermenu {
background: #fff;
border: 1px solid #ddd;
border-top: 0;
}
.leftpanel-collapsed .headerbar {
border-left: 0;
margin-left: -52px;
}
/*** LEFT PANEL ***/
.nav-bracket > li > a {
color: #333;
}
.nav-bracket > li.active > a {
-moz-box-shadow: 0 3px 0 rgba(0, 0, 0, 0.05);
-webkit-box-shadow: 0 3px 0 rgba(0, 0, 0, 0.05);
box-shadow: 0 3px 0 rgba(0, 0, 0, 0.05);
}
.nav-bracket > li > a:hover,
.nav-bracket > li > a:active,
.nav-bracket > li.nav-active > a {
background-color: #eee;
-moz-box-shadow: none;
-webkit-box-shadow: none;
box-shadow: none;
}
.nav-bracket > li.nav-parent > a:hover {
background-color: #eee;
}
.infosummary .datainfo h4 {
color: #333;
}
.infosummary li,
.infosummary ul {
border-color: rgba(0,0,0,0.1);
}
.leftpanel-collapsed .nav-bracket li.nav-hover ul {
background-color: #fff;
}
.leftpanel-collapsed .nav-bracket li a span {
background: #eee;
}
.nav-bracket > li.nav-parent.active > a,
.nav-bracket > li.nav-active.active > a,
.nav-bracket > li.nav-active.active > a:hover {
background-color: #1CAF9A;
}
/*** MAIN PANEL ***/
.pageheader,
.contentpanel {
border-left: 1px solid #e7e7e7;
}
/*** RIGHT PANEL ***/
.rightpanel .nav-tabs {
background: #e4e7ea;
}
.rightpanel .nav-tabs > li > a {
color: rgba(0,0,0,0.5);
}
.rightpanel .nav-tabs > .active > a,
.rightpanel .nav-tabs > .active > a:hover,
.rightpanel .nav-tabs > .active > a:focus {
background-color: #fff;
color: #333;
}
.chatuserlist .online .media-body strong {
color: #1CAF9A;
}
/*** HORIZONTAL MENU ***/
.headerbar .navhor-bracket > li > a {
color: #ccc;
}
.headerbar .logopanel {
border-right: 0;
}
.headerbar .navhor-bracket > li > a {
padding: 15px 15px 13px 15px;
}
.headerbar .navhor-bracket > li .dropdown-menu {
border-top: 0;
}

View File

@@ -0,0 +1,232 @@
tr
{mso-height-source:auto;
mso-ruby-visibility:none;}
col
{mso-width-source:auto;
mso-ruby-visibility:none;}
br
{mso-data-placement:same-cell;}
ruby
{ruby-align:left;}
.style16
{mso-number-format:0%;
mso-style-name:;
mso-style-id:5;}
.style17
{mso-number-format:"_-* \#\,\#\#0_-\;\\-* \#\,\#\#0_-\;_-* \0022-\0022_-\;_-\@_-";
mso-style-name:"쉼표 \[0\]";
mso-style-id:6;}
.style0
{mso-number-format:General;
text-align:general;
vertical-align:middle;
white-space:nowrap;
mso-rotate:0;
mso-background-source:auto;
mso-pattern:auto;
color:black;
font-size:11.0pt;
font-weight:400;
font-style:normal;
text-decoration:none;
font-family:"맑은 고딕";
mso-generic-font-family:auto;
mso-font-charset:129;
border:none;
mso-protection:locked visible;
mso-style-name:;
mso-style-id:0;}
.font12
{color:windowtext;
font-size:17.0pt;
font-weight:700;
font-style:normal;
text-decoration:none;
font-family:"맑은 고딕";
mso-generic-font-family:auto;
mso-font-charset:129;}
td
{mso-style-parent:style0;
padding:0px;
mso-ignore:padding;
color:black;
font-size:11.0pt;
font-weight:400;
font-style:normal;
text-decoration:none;
font-family:"맑은 고딕";
mso-generic-font-family:auto;
mso-font-charset:129;
mso-number-format:General;
text-align:general;
vertical-align:middle;
border:none;
mso-background-source:auto;
mso-pattern:auto;
mso-protection:locked visible;
white-space:nowrap;
mso-rotate:0;}
.sch-table-header-line {
border-top: .5pt solid #1B587C;
border-right:.5pt solid #DAE8F2;
}
.sch-table-header-line:last-child {
border-top: .5pt solid #1B587C;
}
.sch-table-footer-line {
border-bottom: .5pt solid #1B587C !important;
border-right:.5pt solid #DAE8F2;
}
.sch-table-footer-line:last-child {
border-bottom: .5pt solid #1B587C;
border-right:none;
}
.sch-table-header-td {
mso-style-parent:style0;
height:25.0pt;
color:white;
font-size:10.0pt;
font-weight:700;
text-align:center;
border-right:none;
border-bottom:.5pt solid #DAE8F2;
border-right:.5pt solid #DAE8F2;
border-left:none;
background:#1B587C;
mso-pattern:black none;
}
.sch-table-header-td:last-child {
mso-style-parent:style0;
height:25.0pt;
color:white;
font-size:10.0pt;
font-weight:700;
text-align:center;
border-right:none;
border-bottom:.5pt solid #DAE8F2;
border-left:none;
background:#1B587C;
mso-pattern:black none;
}
.sch-table-header-title{
font-size:9.0pt;
color:#1B587C;
font-weight:700;
text-decoration:none;
text-underline-style:none;
text-line-through: none;
font-family:"맑은 고딕", monospace;
mso-font-charset:129;
border-top:.5pt solid #1B587C;
border-right:.5pt solid #DAE8F2;
border-bottom:.5pt solid #1B587C !important;
border-left: none;
background:white;
mso-pattern:black none
}
.sch-table-header-title:last-child{
font-size:9.0pt;
color:#1B587C;
font-weight:700;
text-decoration:none;
text-underline-style:none;
text-line-through: none;
font-family:"맑은 고딕", monospace;
mso-font-charset:129;
border-top:.5pt solid #1B587C;
border-right: none;
border-bottom:.5pt solid #1B587C;
border-left: none;
background:white;
mso-pattern:black none
}
.sch-table-body-td{
height:25.0pt;
color:#404040;
font-weight:400;
text-decoration:none;
text-underline-style:none;
text-line-through: none;
font-family:"맑은 고딕", monospace;
mso-font-charset:129;
border-top:.5pt solid #D9EAD5;
border-right:.5pt solid #DAE8F2 !important;
border-bottom:.5pt solid #DAE8F2 !important;
border-left: none;
}
.sch-table-body-td:last-child{
height:25.0pt;
font-size:9.0pt;
color:#404040;
font-weight:400;
text-decoration:none;
text-underline-style:none;
text-line-through: none;
font-family:"맑은 고딕", monospace;
mso-font-charset:129;
border-top:.5pt solid #D9EAD5;
border-right:none !important;
border-bottom:.5pt solid #DAE8F2;
border-left: none;
}
.sch-table-body-title
{mso-style-parent:style0;
color:#1B587C;
font-size:10.0pt;
font-weight:700;
mso-number-format:"Short Date";
text-align:center;
border-top:.5pt solid #DAE8F2;
border-right:none;
border-bottom:.5pt solid #1B587C;
border-left:none;}
.week-sat {
color:#0070C0;
background: none;
}
.week-sun {
color:#D96A75;
background: none;
}
.sch-table-bg {
background:#E8F3F8;
}
.sch-table-bg2 {
background: #f3f7fa;
}
/* 상단 버튼 정렬 */
.left-btn {
float: left; /* 왼쪽으로 정렬 */
margin-left: 0px !important; /* 각 버튼 사이의 간격 조정 */
margin-right: 10px; /* 각 버튼 사이의 간격 조정 */
}
/* 오른쪽 버튼 정렬을 위한 추가 스타일 */
.right-btn {
float: right; /* 오른쪽으로 정렬 */
}
/* 부모 div의 높이를 자식 요소에 맞추기 위한 스타일 */
.clearfix:after {
content: "";
display: table;
clear: both;
padding-bottom: 5px;
}
.scrollable-div {
max-height: 450px !important;
overflow-y: auto !important;
}

View File

@@ -0,0 +1,243 @@
body {
background: #DCDDDF url(http://cssdeck.com/uploads/media/items/7/7AF2Qzt.png);
color: #000;
font: 14px Arial;
margin: 0 auto;
padding: 0;
position: relative;
}
h1{ font-size:28px;}
h2{ font-size:26px;}
h3{ font-size:18px;}
h4{ font-size:16px;}
h5{ font-size:14px;}
h6{ font-size:12px;}
h1,h2,h3,h4,h5,h6{ color:#563D64;}
small{ font-size:10px;}
b, strong{ font-weight:bold;}
a{ text-decoration: none; }
a:hover{ text-decoration: underline; }
.left { float:left; }
.right { float:right; }
.alignleft { float: left; margin-right: 15px; }
.alignright { float: right; margin-left: 15px; }
.clearfix:after,
form:after {
content: ".";
display: block;
height: 0;
clear: both;
visibility: hidden;
}
.container { margin: 25px auto; position: relative; }
#content {
background: #f9f9f9;
background: -moz-linear-gradient(top, rgba(248,248,248,1) 0%, rgba(249,249,249,1) 100%);
background: -webkit-linear-gradient(top, rgba(248,248,248,1) 0%,rgba(249,249,249,1) 100%);
background: -o-linear-gradient(top, rgba(248,248,248,1) 0%,rgba(249,249,249,1) 100%);
background: -ms-linear-gradient(top, rgba(248,248,248,1) 0%,rgba(249,249,249,1) 100%);
background: linear-gradient(top, rgba(248,248,248,1) 0%,rgba(249,249,249,1) 100%);
filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#f8f8f8', endColorstr='#f9f9f9',GradientType=0 );
-webkit-box-shadow: 0 1px 0 #fff inset;
-moz-box-shadow: 0 1px 0 #fff inset;
-ms-box-shadow: 0 1px 0 #fff inset;
-o-box-shadow: 0 1px 0 #fff inset;
box-shadow: 0 1px 0 #fff inset;
border: 1px solid #c4c6ca;
margin: 0 auto;
padding: 25px 0 0;
position: relative;
text-align: center;
text-shadow: 0 1px 0 #fff;
width: 400px;
}
#content h1 {
color: #7E7E7E;
font: bold 25px Helvetica, Arial, sans-serif;
letter-spacing: -0.05em;
line-height: 20px;
margin: 10px 0 30px;
}
#content h1:before,
#content h1:after {
content: "";
height: 1px;
position: absolute;
top: 10px;
width: 27%;
}
#content h1:after {
background: rgb(126,126,126);
background: -moz-linear-gradient(left, rgba(126,126,126,1) 0%, rgba(255,255,255,1) 100%);
background: -webkit-linear-gradient(left, rgba(126,126,126,1) 0%,rgba(255,255,255,1) 100%);
background: -o-linear-gradient(left, rgba(126,126,126,1) 0%,rgba(255,255,255,1) 100%);
background: -ms-linear-gradient(left, rgba(126,126,126,1) 0%,rgba(255,255,255,1) 100%);
background: linear-gradient(left, rgba(126,126,126,1) 0%,rgba(255,255,255,1) 100%);
right: 0;
}
#content h1:before {
background: rgb(126,126,126);
background: -moz-linear-gradient(right, rgba(126,126,126,1) 0%, rgba(255,255,255,1) 100%);
background: -webkit-linear-gradient(right, rgba(126,126,126,1) 0%,rgba(255,255,255,1) 100%);
background: -o-linear-gradient(right, rgba(126,126,126,1) 0%,rgba(255,255,255,1) 100%);
background: -ms-linear-gradient(right, rgba(126,126,126,1) 0%,rgba(255,255,255,1) 100%);
background: linear-gradient(right, rgba(126,126,126,1) 0%,rgba(255,255,255,1) 100%);
left: 0;
}
#content:after,
#content:before {
background: #f9f9f9;
background: -moz-linear-gradient(top, rgba(248,248,248,1) 0%, rgba(249,249,249,1) 100%);
background: -webkit-linear-gradient(top, rgba(248,248,248,1) 0%,rgba(249,249,249,1) 100%);
background: -o-linear-gradient(top, rgba(248,248,248,1) 0%,rgba(249,249,249,1) 100%);
background: -ms-linear-gradient(top, rgba(248,248,248,1) 0%,rgba(249,249,249,1) 100%);
background: linear-gradient(top, rgba(248,248,248,1) 0%,rgba(249,249,249,1) 100%);
filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#f8f8f8', endColorstr='#f9f9f9',GradientType=0 );
border: 1px solid #c4c6ca;
content: "";
display: block;
height: 100%;
left: -1px;
position: absolute;
width: 100%;
}
#content:after {
-webkit-transform: rotate(2deg);
-moz-transform: rotate(2deg);
-ms-transform: rotate(2deg);
-o-transform: rotate(2deg);
transform: rotate(2deg);
top: 0;
z-index: -1;
}
#content:before {
-webkit-transform: rotate(-3deg);
-moz-transform: rotate(-3deg);
-ms-transform: rotate(-3deg);
-o-transform: rotate(-3deg);
transform: rotate(-3deg);
top: 0;
z-index: -2;
}
#content form { margin: 0 20px; position: relative }
#content form input[type="text"],
#content form input[type="password"] {
-webkit-border-radius: 3px;
-moz-border-radius: 3px;
-ms-border-radius: 3px;
-o-border-radius: 3px;
border-radius: 3px;
-webkit-box-shadow: 0 1px 0 #fff, 0 -2px 5px rgba(0,0,0,0.08) inset;
-moz-box-shadow: 0 1px 0 #fff, 0 -2px 5px rgba(0,0,0,0.08) inset;
-ms-box-shadow: 0 1px 0 #fff, 0 -2px 5px rgba(0,0,0,0.08) inset;
-o-box-shadow: 0 1px 0 #fff, 0 -2px 5px rgba(0,0,0,0.08) inset;
box-shadow: 0 1px 0 #fff, 0 -2px 5px rgba(0,0,0,0.08) inset;
-webkit-transition: all 0.5s ease;
-moz-transition: all 0.5s ease;
-ms-transition: all 0.5s ease;
-o-transition: all 0.5s ease;
transition: all 0.5s ease;
background: #eae7e7 url(http://cssdeck.com/uploads/media/items/8/8bcLQqF.png) no-repeat;
border: 1px solid #c8c8c8;
color: #777;
font: 13px Helvetica, Arial, sans-serif;
margin: 0 0 10px;
padding: 15px 10px 15px 40px;
width: 80%;
}
#content form input[type="text"]:focus,
#content form input[type="password"]:focus {
-webkit-box-shadow: 0 0 2px #ed1c24 inset;
-moz-box-shadow: 0 0 2px #ed1c24 inset;
-ms-box-shadow: 0 0 2px #ed1c24 inset;
-o-box-shadow: 0 0 2px #ed1c24 inset;
box-shadow: 0 0 2px #ed1c24 inset;
background-color: #fff;
border: 1px solid #ed1c24;
outline: none;
}
#username { background-position: 10px 10px !important }
#password { background-position: 10px -53px !important }
#content form input[type="submit"] {
background: rgb(254,231,154);
background: -moz-linear-gradient(top, rgba(254,231,154,1) 0%, rgba(254,193,81,1) 100%);
background: -webkit-linear-gradient(top, rgba(254,231,154,1) 0%,rgba(254,193,81,1) 100%);
background: -o-linear-gradient(top, rgba(254,231,154,1) 0%,rgba(254,193,81,1) 100%);
background: -ms-linear-gradient(top, rgba(254,231,154,1) 0%,rgba(254,193,81,1) 100%);
background: linear-gradient(top, rgba(254,231,154,1) 0%,rgba(254,193,81,1) 100%);
filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#fee79a', endColorstr='#fec151',GradientType=0 );
-webkit-border-radius: 30px;
-moz-border-radius: 30px;
-ms-border-radius: 30px;
-o-border-radius: 30px;
border-radius: 30px;
-webkit-box-shadow: 0 1px 0 rgba(255,255,255,0.8) inset;
-moz-box-shadow: 0 1px 0 rgba(255,255,255,0.8) inset;
-ms-box-shadow: 0 1px 0 rgba(255,255,255,0.8) inset;
-o-box-shadow: 0 1px 0 rgba(255,255,255,0.8) inset;
box-shadow: 0 1px 0 rgba(255,255,255,0.8) inset;
border: 1px solid #D69E31;
color: #85592e;
cursor: pointer;
float: left;
font: bold 15px Helvetica, Arial, sans-serif;
height: 35px;
margin: 20px 0 35px 120px;
position: relative;
text-shadow: 0 1px 0 rgba(255,255,255,0.5);
width: 120px;
}
#content form input[type="submit"]:hover {
background: rgb(254,193,81);
background: -moz-linear-gradient(top, rgba(254,193,81,1) 0%, rgba(254,231,154,1) 100%);
background: -webkit-linear-gradient(top, rgba(254,193,81,1) 0%,rgba(254,231,154,1) 100%);
background: -o-linear-gradient(top, rgba(254,193,81,1) 0%,rgba(254,231,154,1) 100%);
background: -ms-linear-gradient(top, rgba(254,193,81,1) 0%,rgba(254,231,154,1) 100%);
background: linear-gradient(top, rgba(254,193,81,1) 0%,rgba(254,231,154,1) 100%);
filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#fec151', endColorstr='#fee79a',GradientType=0 );
}
#content form div a {
color: #004a80;
float: right;
font-size: 12px;
margin: 30px 15px 0 0;
text-decoration: underline;
}
.button {
background: rgb(247,249,250);
background: -moz-linear-gradient(top, rgba(247,249,250,1) 0%, rgba(240,240,240,1) 100%);
background: -webkit-linear-gradient(top, rgba(247,249,250,1) 0%,rgba(240,240,240,1) 100%);
background: -o-linear-gradient(top, rgba(247,249,250,1) 0%,rgba(240,240,240,1) 100%);
background: -ms-linear-gradient(top, rgba(247,249,250,1) 0%,rgba(240,240,240,1) 100%);
background: linear-gradient(top, rgba(247,249,250,1) 0%,rgba(240,240,240,1) 100%);
filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#f7f9fa', endColorstr='#f0f0f0',GradientType=0 );
-webkit-box-shadow: 0 1px 2px rgba(0,0,0,0.1) inset;
-moz-box-shadow: 0 1px 2px rgba(0,0,0,0.1) inset;
-ms-box-shadow: 0 1px 2px rgba(0,0,0,0.1) inset;
-o-box-shadow: 0 1px 2px rgba(0,0,0,0.1) inset;
box-shadow: 0 1px 2px rgba(0,0,0,0.1) inset;
-webkit-border-radius: 0 0 5px 5px;
-moz-border-radius: 0 0 5px 5px;
-o-border-radius: 0 0 5px 5px;
-ms-border-radius: 0 0 5px 5px;
border-radius: 0 0 5px 5px;
border-top: 1px solid #CFD5D9;
padding: 15px 0;
}
.button a {
background: url(http://cssdeck.com/uploads/media/items/8/8bcLQqF.png) 0 -112px no-repeat;
color: #7E7E7E;
font-size: 17px;
padding: 2px 0 2px 40px;
text-decoration: none;
-webkit-transition: all 0.3s ease;
-moz-transition: all 0.3s ease;
-ms-transition: all 0.3s ease;
-o-transition: all 0.3s ease;
transition: all 0.3s ease;
}
.button a:hover {
background-position: 0 -135px;
color: #00aeef;
}

View File

@@ -0,0 +1,168 @@
.tablesorter-default {
width: 100%;
font: 12px/18px Arial, Sans-serif;
/*color: #333;*/
/*background-color: #fff;*/
border-spacing: 0;
margin: 10px 0 15px;
text-align: left
}
.tablesorter-default th, .tablesorter-default thead td {
font-weight: 700;
/*color: #000;*/
/*background-color: #fff;*/
border-collapse: collapse;
border-bottom: #ccc 2px solid;
padding: 0
}
.tablesorter-default tfoot td, .tablesorter-default tfoot th {
border: 0
}
.tablesorter-default .header, .tablesorter-default .tablesorter-header {
background-image: url(data:image/gif;base64,R0lGODlhFQAJAIAAACMtMP///yH5BAEAAAEALAAAAAAVAAkAAAIXjI+AywnaYnhUMoqt3gZXPmVg94yJVQAAOw==);
background-position: center right;
background-repeat: no-repeat;
cursor: pointer;
white-space: normal;
padding: 4px 20px 4px 4px
}
.tablesorter-default thead .headerSortUp, .tablesorter-default thead .tablesorter-headerAsc, .tablesorter-default thead .tablesorter-headerSortUp {
background-image: url(data:image/gif;base64,R0lGODlhFQAEAIAAACMtMP///yH5BAEAAAEALAAAAAAVAAQAAAINjI8Bya2wnINUMopZAQA7);
border-bottom: #000 2px solid
}
.tablesorter-default thead .headerSortDown, .tablesorter-default thead .tablesorter-headerDesc, .tablesorter-default thead .tablesorter-headerSortDown {
background-image: url(data:image/gif;base64,R0lGODlhFQAEAIAAACMtMP///yH5BAEAAAEALAAAAAAVAAQAAAINjB+gC+jP2ptn0WskLQA7);
border-bottom: #000 2px solid
}
.tablesorter-default thead .sorter-false {
background-image: none;
cursor: default;
padding: 4px
}
.tablesorter-default tfoot .tablesorter-headerAsc, .tablesorter-default tfoot .tablesorter-headerDesc, .tablesorter-default tfoot .tablesorter-headerSortDown, .tablesorter-default tfoot .tablesorter-headerSortUp {
border-top: #000 2px solid
}
.tablesorter-default td {
/*background-color: #fff;*/
border-bottom: #ccc 1px solid;
padding: 4px;
vertical-align: top
}
.tablesorter-default tbody > tr.even:hover > td, .tablesorter-default tbody > tr.hover > td, .tablesorter-default tbody > tr.odd:hover > td, .tablesorter-default tbody > tr:hover > td {
background-color: #fff;
/*color: #000*/
}
.tablesorter-default .tablesorter-processing {
background-position: center center !important;
background-repeat: no-repeat !important;
background-image: url(data:image/gif;base64,R0lGODlhFAAUAKEAAO7u7lpaWgAAAAAAACH/C05FVFNDQVBFMi4wAwEAAAAh+QQBCgACACwAAAAAFAAUAAACQZRvoIDtu1wLQUAlqKTVxqwhXIiBnDg6Y4eyx4lKW5XK7wrLeK3vbq8J2W4T4e1nMhpWrZCTt3xKZ8kgsggdJmUFACH5BAEKAAIALAcAAAALAAcAAAIUVB6ii7jajgCAuUmtovxtXnmdUAAAIfkEAQoAAgAsDQACAAcACwAAAhRUIpmHy/3gUVQAQO9NetuugCFWAAAh+QQBCgACACwNAAcABwALAAACE5QVcZjKbVo6ck2AF95m5/6BSwEAIfkEAQoAAgAsBwANAAsABwAAAhOUH3kr6QaAcSrGWe1VQl+mMUIBACH5BAEKAAIALAIADQALAAcAAAIUlICmh7ncTAgqijkruDiv7n2YUAAAIfkEAQoAAgAsAAAHAAcACwAAAhQUIGmHyedehIoqFXLKfPOAaZdWAAAh+QQFCgACACwAAAIABwALAAACFJQFcJiXb15zLYRl7cla8OtlGGgUADs=) !important
}
.tablesorter-default tr.odd > td {
background-color: #dfdfdf
}
.tablesorter-default tr.even > td {
background-color: #efefef
}
.tablesorter-default tr.odd td.primary {
background-color: #bfbfbf
}
.tablesorter-default td.primary, .tablesorter-default tr.even td.primary {
background-color: #d9d9d9
}
.tablesorter-default tr.odd td.secondary {
background-color: #d9d9d9
}
.tablesorter-default td.secondary, .tablesorter-default tr.even td.secondary {
background-color: #e6e6e6
}
.tablesorter-default tr.odd td.tertiary {
background-color: #e6e6e6
}
.tablesorter-default td.tertiary, .tablesorter-default tr.even td.tertiary {
background-color: #f2f2f2
}
.tablesorter-default > caption {
background-color: #fff
}
.tablesorter-default .tablesorter-filter-row {
background-color: #eee
}
.tablesorter-default .tablesorter-filter-row td {
background-color: #eee;
border-bottom: #ccc 1px solid;
line-height: normal;
text-align: center;
-webkit-transition: line-height .1s ease;
-moz-transition: line-height .1s ease;
-o-transition: line-height .1s ease;
transition: line-height .1s ease
}
.tablesorter-default .tablesorter-filter-row .disabled {
opacity: .5;
cursor: not-allowed
}
.tablesorter-default .tablesorter-filter-row.hideme td {
padding: 2px;
margin: 0;
line-height: 0;
cursor: pointer
}
.tablesorter-default .tablesorter-filter-row.hideme * {
height: 1px;
min-height: 0;
border: 0;
padding: 0;
margin: 0;
opacity: 0
}
.tablesorter-default input.tablesorter-filter, .tablesorter-default select.tablesorter-filter {
width: 95%;
height: auto;
margin: 4px auto;
padding: 4px;
background-color: #fff;
border: 1px solid #bbb;
/*color: #333;*/
-webkit-box-sizing: border-box;
-moz-box-sizing: border-box;
box-sizing: border-box;
-webkit-transition: height .1s ease;
-moz-transition: height .1s ease;
-o-transition: height .1s ease;
transition: height .1s ease
}
.tablesorter .filtered {
display: none
}
.tablesorter .tablesorter-errorRow td {
text-align: center;
cursor: pointer;
background-color: #e6bf99
}

View File

@@ -0,0 +1,261 @@
.toggle-slide {
overflow: hidden;
cursor: pointer;
-webkit-touch-callout: none;
-webkit-user-select: none;
-khtml-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
direction: ltr;
}
.toggle-slide .toggle-on,.toggle-slide .toggle-off,.toggle-slide .toggle-blob {
float: left;
}
.toggle-slide .toggle-blob {
position: relative;
z-index: 99;
cursor: hand;
cursor: grab;
cursor: -moz-grab;
cursor: -webkit-grab;
}
.toggle-slide {
overflow: hidden;
cursor: pointer;
-webkit-touch-callout: none;
-webkit-user-select: none;
-khtml-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
direction: ltr;
}
.toggle-slide .toggle-on,.toggle-slide .toggle-off,.toggle-slide .toggle-blob {
float: left;
}
.toggle-slide .toggle-blob {
position: relative;
z-index: 99;
cursor: hand;
cursor: grab;
cursor: -moz-grab;
cursor: -webkit-grab;
}
/*** THEMES ***/
.toggle-default .toggle-slide {
border: 1px solid #ccc;
margin-top: -5px;
}
.toggle-default .toggle-slide.active {
border-color: #999;
}
.toggle-default .toggle-slide .toggle-on,
.toggle-default .toggle-slide .toggle-off,
.toggle-default .toggle-slide .toggle-blob {
font-size: 11px;
font-weight: 500;
}
.toggle-default .toggle-slide .toggle-on,
.toggle-default .toggle-select .toggle-inner .active {
background: #999;
color: #fff;
}
.toggle-default .toggle-slide .toggle-off,
.toggle-default .toggle-select .toggle-on {
color: #666;
background: #f7f7f7;
}
.toggle-default .toggle-slide .toggle-blob {
background: #fff;
border-right: 1px solid #ccc;
}
.toggle-default .toggle-slide.active .toggle-blob {
border-left: 1px solid #999;
border-right: 0;
}
.toggle-default .toggle-slide .toggle-blob:hover {
background: #fcfcfc;
}
/* toggle primary */
.toggle-primary .toggle-slide {
border: 1px solid #999;
}
.toggle-primary .toggle-slide.active {
border-color: #357EBD;
}
.toggle-primary .toggle-slide .toggle-on,
.toggle-primary .toggle-slide .toggle-off,
.toggle-primary .toggle-slide .toggle-blob {
font-size: 11px;
font-weight: 500;
}
.toggle-primary .toggle-slide .toggle-on,
.toggle-primary .toggle-select .toggle-inner .active {
background: #428BCA;
color: #fff;
}
.toggle-primary .toggle-slide .toggle-off,
.toggle-primary .toggle-select .toggle-on {
color: #fff;
background: #bbb;
}
.toggle-primary .toggle-slide .toggle-blob {
background: #fff;
border-right: 1px solid #999;
}
.toggle-primary .toggle-slide.active .toggle-blob {
border-left: 1px solid #357EBD;
border-right: 0;
}
.toggle-primary .toggle-slide .toggle-blob:hover {
background: #fcfcfc;
}
/* toggle success */
.toggle-success .toggle-slide {
border: 1px solid #999;
}
.toggle-success .toggle-slide.active {
border-color: #1CAF9A;
}
.toggle-success .toggle-slide .toggle-on,
.toggle-success .toggle-slide .toggle-off,
.toggle-success .toggle-slide .toggle-blob {
font-size: 11px;
font-weight: 500;
}
.toggle-success .toggle-slide .toggle-on,
.toggle-success .toggle-select .toggle-inner .active {
background: #1CAF9A;
color: #fff;
}
.toggle-success .toggle-slide .toggle-off,
.toggle-success .toggle-select .toggle-on {
color: #fff;
background: #bbb;
}
.toggle-success .toggle-slide .toggle-blob {
background: #fff;
border-right: 1px solid #999;
}
.toggle-success .toggle-slide.active .toggle-blob {
border-left: 1px solid #4CAE4C;
border-right: 0;
}
.toggle-success .toggle-slide .toggle-blob:hover {
background: #fcfcfc;
}
/* toggle warning */
.toggle-warning .toggle-slide {
border: 1px solid #999;
}
.toggle-warning .toggle-slide.active {
border-color: #EEA236;
}
.toggle-warning .toggle-slide .toggle-on,
.toggle-warning .toggle-slide .toggle-off,
.toggle-warning .toggle-slide .toggle-blob {
font-size: 11px;
font-weight: 500;
}
.toggle-warning .toggle-slide .toggle-on,
.toggle-warning .toggle-select .toggle-inner .active {
background: #F0AD4E;
color: #fff;
}
.toggle-warning .toggle-slide .toggle-off,
.toggle-warning .toggle-select .toggle-on {
color: #fff;
background: #bbb;
}
.toggle-warning .toggle-slide .toggle-blob {
background: #fff;
border-right: 1px solid #999;
}
.toggle-warning .toggle-slide.active .toggle-blob {
border-left: 1px solid #EEA236;
border-right: 0;
}
.toggle-warning .toggle-slide .toggle-blob:hover {
background: #fcfcfc;
}
/* toggle danger */
.toggle-danger .toggle-slide {
border: 1px solid #999;
}
.toggle-danger .toggle-slide.active {
border-color: #D43F3A;
}
.toggle-danger .toggle-slide .toggle-on,
.toggle-danger .toggle-slide .toggle-off,
.toggle-danger .toggle-slide .toggle-blob {
font-size: 11px;
font-weight: 500;
}
.toggle-danger .toggle-slide .toggle-on,
.toggle-danger .toggle-select .toggle-inner .active {
background: #D9534F;
color: #fff;
}
.toggle-danger .toggle-slide .toggle-off,
.toggle-danger .toggle-select .toggle-on {
color: #fff;
background: #bbb;
}
.toggle-danger .toggle-slide .toggle-blob {
background: #fff;
border-right: 1px solid #999;
}
.toggle-danger .toggle-slide.active .toggle-blob {
border-left: 1px solid #D43F3A;
border-right: 0;
}
.toggle-danger .toggle-slide .toggle-blob:hover {
background: #fcfcfc;
}

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

Binary file not shown.

View File

@@ -0,0 +1,16 @@
// Bordered & Pulled
// -------------------------
.@{fa-css-prefix}-border {
padding: .2em .25em .15em;
border: solid .08em @fa-border-color;
border-radius: .1em;
}
.pull-right { float: right; }
.pull-left { float: left; }
.@{fa-css-prefix} {
&.pull-left { margin-right: .3em; }
&.pull-right { margin-left: .3em; }
}

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