1
0
mirror of https://github.com/Cekis/swg-web.git synced 2026-01-17 00:06:55 -05:00

Initial Commit - Most settings are now available.

This commit is contained in:
Cekis
2021-03-25 00:15:12 -07:00
commit 8885f2e7eb
80 changed files with 36290 additions and 0 deletions

17
.eslintrc.js Normal file
View File

@@ -0,0 +1,17 @@
module.exports = {
root: true,
env: {
node: true
},
'extends': [
'plugin:vue/essential',
'eslint:recommended'
],
rules: {
'no-console': process.env.NODE_ENV === 'production' ? 'error' : 'off',
'no-debugger': process.env.NODE_ENV === 'production' ? 'error' : 'off'
},
parserOptions: {
parser: 'babel-eslint'
}
}

22
.gitignore vendored Normal file
View File

@@ -0,0 +1,22 @@
.DS_Store
node_modules/
/dist/
# local env files
.env.local
.env.*.local
# Log files
npm-debug.log*
yarn-debug.log*
yarn-error.log*
# Editor directories and files
.idea
.vscode
*.suo
*.ntvs*
*.njsproj
*.sln
*.sw*

5
.postcssrc.js Normal file
View File

@@ -0,0 +1,5 @@
module.exports = {
plugins: {
autoprefixer: {}
}
}

11
babel.config.js Normal file
View File

@@ -0,0 +1,11 @@
module.exports = {
presets: [
[
'@babel/preset-env',
{
useBuiltIns: 'entry',
corejs: 3
}
]
]
}

31
jest.config.js Normal file
View File

@@ -0,0 +1,31 @@
const ignoredModules = ['@coreui/icons', '@coreui/utils'].join('|')
module.exports = {
moduleFileExtensions: [
'js',
'jsx',
'json',
'vue'
],
transform: {
'^.+\\.vue$': 'vue-jest',
'.+\\.(css|styl|less|sass|scss|png|jpg|ttf|woff|woff2)$': 'jest-transform-stub',
'^.+\\.(js|jsx)?$': '<rootDir>/node_modules/babel-jest'
},
transformIgnorePatterns: [`<rootDir>/node_modules/(?!${ignoredModules})`],
moduleNameMapper: {
'^@/(.*)$': '<rootDir>/src/$1'
},
snapshotSerializers: [
'jest-serializer-vue'
],
testMatch: ['<rootDir>/tests/unit/**/*.spec.js'],
verbose: true,
testURL: 'http://localhost/',
collectCoverage: true,
collectCoverageFrom: [
'src/**/*.{js,vue}',
'!**/node_modules/**'
],
coverageReporters: ['html', 'text-summary']
}

17494
package-lock.json generated Normal file

File diff suppressed because it is too large Load Diff

78
package.json Normal file
View File

@@ -0,0 +1,78 @@
{
"name": "@coreui/coreui-free-vue-admin-template",
"version": "3.1.2",
"description": "Open Source Bootstrap Admin Template",
"author": {
"name": "CoreUI",
"url": "https://coreui.io",
"github": "https://github.com/coreui",
"twitter": "https://twitter.com/core_ui"
},
"contributors": [
{
"name": "CoreUI Team",
"url": "https://github.com/orgs/coreui/people"
}
],
"repository": {
"type": "git",
"url": "git@github.com:coreui/coreui-free-vue-admin-template.git"
},
"homepage": "http://coreui.io",
"copyright": "Copyright 2020 creativeLabs Łukasz Holeczek",
"license": "MIT",
"scripts": {
"serve": "vue-cli-service serve",
"build": "vue-cli-service build",
"lint": "vue-cli-service lint",
"test:unit": "vue-cli-service test:unit",
"test:e2e": "vue-cli-service test:e2e",
"clearCache": "jest --clearCache",
"release": "npm-run-all clearCache lint build test:unit test:e2e",
"auto-changelog": "auto-changelog --hide-credit --commit-limit false --package --backfill-limit 0 --starting-version 3.0.0-beta.0"
},
"dependencies": {
"@coreui/coreui": "^3.4.0",
"@coreui/icons": "^2.0.0-rc.0",
"@coreui/icons-pro": "^2.0.0-beta.5",
"@coreui/utils": "^1.3.1",
"@coreui/vue": "^3.2.7",
"@coreui/vue-chartjs": "^1.0.6",
"axios": "^0.21.1",
"lodash": "^4.17.21",
"prettier": "^2.2.1",
"vue": "~2.6.12",
"vue-axios": "^3.2.4",
"vue-router": "^3.5.1",
"vuex": "~3.6.0"
},
"devDependencies": {
"@babel/core": "^7.12.10",
"@vue/cli-plugin-babel": "^4.5.9",
"@vue/cli-plugin-e2e-nightwatch": "^4.5.9",
"@vue/cli-plugin-eslint": "^4.5.9",
"@vue/cli-plugin-unit-jest": "^4.5.9",
"@vue/cli-service": "^4.5.9",
"@vue/test-utils": "^1.1.2",
"auto-changelog": "^2.2.1",
"babel-eslint": "~10.1.0",
"babel-jest": "~26.3.0",
"chromedriver": "^87.0.4",
"core-js": "^3.8.2",
"eslint": "^7.17.0",
"eslint-plugin-vue": "^6.2.2",
"node-sass": "~4.14.1",
"npm-run-all": "~4.1.5",
"sass-loader": "^10.0.5",
"vue-template-compiler": "~2.6.12"
},
"browserslist": [
"> 1%",
"last 2 versions",
"not ie < 11"
],
"engines": {
"node": ">= 12.x",
"npm": ">= 6.x"
}
}

2
public/browserconfig.xml Normal file
View File

@@ -0,0 +1,2 @@
<?xml version="1.0" encoding="utf-8"?>
<browserconfig><msapplication><tile><square70x70logo src="/ms-icon-70x70.png"/><square150x150logo src="/ms-icon-150x150.png"/><square310x310logo src="/ms-icon-310x310.png"/><TileColor>#ffffff</TileColor></tile></msapplication></browserconfig>

1
public/config.js Normal file
View File

@@ -0,0 +1 @@
const SERVER_URL = 'http://localhost:8080/api';

BIN
public/favicon.ico Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

37
public/index.html Normal file
View File

@@ -0,0 +1,37 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width,initial-scale=1.0" />
<title>SWG-Source: Server Management Console</title>
<link rel="manifest" href="/manifest.json" />
<meta name="msapplication-TileColor" content="#ffffff" />
<meta name="theme-color" content="#ffffff" />
<!-- local config -->
<script src="./config.js"></script>
<script>
window.dataLayer = window.dataLayer || [];
function gtag() {
dataLayer.push(arguments);
}
gtag('js', new Date());
// Shared ID
gtag('config', 'UA-118965717-3');
// Vue.js ID
gtag('config', 'UA-118965717-7');
</script>
</head>
<body>
<noscript>
<strong
>We're sorry but this app doesn't work properly without JavaScript
enabled. Please enable it to continue.</strong
>
</noscript>
<div id="app"></div>
<!-- built files will be auto injected -->
</body>
</html>

4
public/manifest.json Normal file
View File

@@ -0,0 +1,4 @@
{
"name": "App",
"icons": []
}

17
src/App.vue Normal file
View File

@@ -0,0 +1,17 @@
<template>
<router-view></router-view>
</template>
<script>
export default {
name: 'App',
created() {
this.$store.dispatch('settings/fetchAll');
},
};
</script>
<style lang="scss">
// Import Main styles for this application
@import 'assets/scss/style';
</style>

5
src/AxiosClient.js Normal file
View File

@@ -0,0 +1,5 @@
const axios = require('axios').default;
axios.defaults.headers.common['X-Requested-With'] = 'XMLHttpRequest';
export { axios as client };

23
src/api/city-api.js Normal file
View File

@@ -0,0 +1,23 @@
import config from './config';
import { Promise } from 'core-js';
const client = config.client;
export default {
all() {
return new Promise((resolve, reject) => {
client
.get(`${SERVER_URL}/city/all`)
.then((r) => resolve(r.data))
.catch((e) => reject(e));
});
},
getCityDetail(name) {
return new Promise((resolve, reject) => {
client
.get(`${SERVER_URL}/city/detail?name=${name}`)
.then((r) => resolve(r.data))
.catch((e) => reject(e));
});
},
};

5
src/api/config.js Normal file
View File

@@ -0,0 +1,5 @@
import { client } from '@/AxiosClient';
export default {
client,
};

23
src/api/faction-api.js Normal file
View File

@@ -0,0 +1,23 @@
import config from './config';
import { Promise } from 'core-js';
const client = config.client;
export default {
all() {
return new Promise((resolve, reject) => {
client
.get('/faction/all')
.then((r) => resolve(r.data))
.catch((e) => reject(e));
});
},
getFaction(factionId) {
return new Promise((resolve, reject) => {
client
.get(`/faction/${factionId}`)
.then((r) => resolve(r))
.catch((e) => reject(e));
});
},
};

11
src/api/index.js Normal file
View File

@@ -0,0 +1,11 @@
import config from './config';
import city from './city-api';
import player from './player-api';
import settings from './settings-api';
export default {
config,
city,
player,
settings,
};

23
src/api/player-api.js Normal file
View File

@@ -0,0 +1,23 @@
import config from './config';
import { Promise } from 'core-js';
const client = config.client;
export default {
all() {
return new Promise((resolve, reject) => {
client
.get('/player/all')
.then((r) => resolve(r.data))
.catch((e) => reject(e));
});
},
getPlayerDetail(objectId) {
return new Promise((resolve, reject) => {
client
.get(`${SERVER_URL}/player/${objectId}`)
.then((r) => resolve(r.data))
.catch((e) => reject(e));
});
},
};

15
src/api/settings-api.js Normal file
View File

@@ -0,0 +1,15 @@
import config from './config';
import { Promise } from 'core-js';
const client = config.client;
export default {
all() {
return new Promise((resolve, reject) => {
client
.get(`${SERVER_URL}/settings/server`)
.then((r) => resolve(r.data))
.catch((e) => reject(e));
});
},
};

0
src/assets/.gitkeep Normal file
View File

BIN
src/assets/favicon.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 136 KiB

180
src/assets/icons/icons.js Normal file
View File

@@ -0,0 +1,180 @@
import {
cibFacebook,
cibTwitter,
cibLinkedin,
cibFlickr,
cibTumblr,
cibXing,
cibGithub,
cibStackoverflow,
cibYoutube,
cibDribbble,
cibInstagram,
cibPinterest,
cibVk,
cibYahoo,
cibBehance,
cibReddit,
cibVimeo,
cibCcMastercard,
cibCcVisa,
cibStripe,
cibPaypal,
cibGooglePay,
cibCcAmex,
} from '@coreui/icons';
import { cifUs, cifBr, cifIn, cifFr, cifEs, cifPl } from '@coreui/icons';
import {
cilArrowRight,
cilBan,
cilBank,
cilBarChart,
cilBasket,
cilBell,
cilBuilding,
cilCalculator,
cilCalendar,
cilCloudDownload,
cilChartPie,
cilCheck,
cilChevronBottom,
cilChevronTop,
cilCheckCircle,
cilCommentSquare,
cilCursor,
cilDrop,
cilDollar,
cilEnvelopeClosed,
cilEnvelopeOpen,
cilEuro,
cilGlobeAlt,
cilGrid,
cilFile,
cilHealing,
cilHome,
cilJustifyCenter,
cilLaptop,
cilLayers,
cilLeaf,
cilLightbulb,
cilList,
cilLocationPin,
cilLockLocked,
cilMagnifyingGlass,
cilMoney,
cilMoon,
cilOptions,
cilPencil,
cilPeople,
cilPuzzle,
cilSchool,
cilSettings,
cilShieldAlt,
cilSpeech,
cilSpeedometer,
cilStar,
cilTask,
cilTerrain,
cilUser,
cilUserFemale,
cilUserFollow,
cilXCircle,
} from '@coreui/icons';
import { logo } from './logo';
import { cilCommentBubbleQuestion } from '@coreui/icons-pro';
export const iconsSet = Object.assign(
{},
{ logo },
{
cilArrowRight,
cilBan,
cilBank,
cilBarChart,
cilBasket,
cilBell,
cilBuilding,
cilCalculator,
cilCalendar,
cilCloudDownload,
cilChartPie,
cilCheck,
cilChevronBottom,
cilChevronTop,
cilCheckCircle,
cilCommentBubbleQuestion,
cilCommentSquare,
cilCursor,
cilDrop,
cilDollar,
cilEnvelopeClosed,
cilEnvelopeOpen,
cilEuro,
cilGlobeAlt,
cilGrid,
cilFile,
cilHealing,
cilHome,
cilJustifyCenter,
cilLaptop,
cilLayers,
cilLeaf,
cilLightbulb,
cilList,
cilLocationPin,
cilLockLocked,
cilMagnifyingGlass,
cilMoney,
cilMoon,
cilOptions,
cilPencil,
cilPeople,
cilPuzzle,
cilSchool,
cilSettings,
cilShieldAlt,
cilSpeech,
cilSpeedometer,
cilStar,
cilTask,
cilTerrain,
cilUser,
cilUserFemale,
cilUserFollow,
cilXCircle,
},
{
cifUs,
cifBr,
cifIn,
cifFr,
cifEs,
cifPl,
},
{
cibFacebook,
cibTwitter,
cibLinkedin,
cibFlickr,
cibTumblr,
cibXing,
cibGithub,
cibStackoverflow,
cibYoutube,
cibDribbble,
cibInstagram,
cibPinterest,
cibVk,
cibYahoo,
cibBehance,
cibReddit,
cibVimeo,
cibCcMastercard,
cibCcVisa,
cibStripe,
cibPaypal,
cibGooglePay,
cibCcAmex,
}
);

29
src/assets/icons/logo.js Normal file
View File

@@ -0,0 +1,29 @@
// Example of SVG converted to js array, so it can be used with CIcon.
// the first argument is two last values of svg viewBox,
// the second argument is the SVG content stripped of SVG tags
export const logo = ['556 134',`
<g>
<g style="fill:#1bbd93;">
<path d="M347.9818,90.0869l-11.84-43.52-.0644-.1924q0-.5112.6406-.5117h1.2793a.66.66,0,0,1,.7051.5762l10.623,39.68c.042.0859.0859.1279.1289.1279.041,0,.084-.042.127-.1279l10.625-39.68a.657.657,0,0,1,.7031-.5762h1.2168a.54.54,0,0,1,.5762.7041l-11.9043,43.52a.6584.6584,0,0,1-.7041.5761h-1.4082A.6577.6577,0,0,1,347.9818,90.0869Z"/>
<path d="M382.2786,89.5751a10.9023,10.9023,0,0,1-4.3515-4.5439,14.4586,14.4586,0,0,1-1.5362-6.7842V46.5029a.5656.5656,0,0,1,.64-.64h1.2168a.5659.5659,0,0,1,.64.64v32a10.5488,10.5488,0,0,0,2.72,7.5527,10.36,10.36,0,0,0,14.3359,0,10.5493,10.5493,0,0,0,2.7207-7.5527v-32a.5655.5655,0,0,1,.64-.64h1.2159a.5666.5666,0,0,1,.6406.64V78.247a13.01,13.01,0,0,1-3.3926,9.376,11.8974,11.8974,0,0,1-9.0234,3.5527A12.8481,12.8481,0,0,1,382.2786,89.5751Z"/>
<path d="M439.5843,48.1035H419.5521a.2263.2263,0,0,0-.2559.2558V66.8554a.2259.2259,0,0,0,.2559.2559h13.8242a.5665.5665,0,0,1,.6406.64v.96a.5665.5665,0,0,1-.6406.6406H419.5521a.2263.2263,0,0,0-.2559.2559v18.56a.2259.2259,0,0,0,.2559.2559h20.0322a.5665.5665,0,0,1,.64.6406v.96a.5655.5655,0,0,1-.64.64H417.4407a.5654.5654,0,0,1-.6406-.64v-43.52a.5658.5658,0,0,1,.6406-.64h22.1436a.5659.5659,0,0,1,.64.64v.96A.5658.5658,0,0,1,439.5843,48.1035Z"/>
<path d="M454.5921,89.5117a2.8385,2.8385,0,0,1-.8-2.0489,2.9193,2.9193,0,0,1,.8-2.1113,2.7518,2.7518,0,0,1,2.0791-.832,2.8465,2.8465,0,0,1,2.9443,2.9433,2.7561,2.7561,0,0,1-.832,2.08,2.9208,2.9208,0,0,1-2.1123.8008A2.7521,2.7521,0,0,1,454.5921,89.5117Z"/>
<path d="M474.931,88.0078a11.3087,11.3087,0,0,1-3.2-8.4161v-5.44a.5655.5655,0,0,1,.64-.64h1.2158a.5662.5662,0,0,1,.6407.64v5.5039a9.1421,9.1421,0,0,0,2.5283,6.72,8.9734,8.9734,0,0,0,6.6875,2.5606,8.7916,8.7916,0,0,0,9.28-9.28V46.5029a.5655.5655,0,0,1,.64-.64h1.2158a.5656.5656,0,0,1,.64.64V79.5917a11.2541,11.2541,0,0,1-3.2315,8.4161,13.0621,13.0621,0,0,1-17.0556,0Z"/>
<path d="M512.8753,88.1035a10.4847,10.4847,0,0,1-3.36-8.128v-1.792a.5665.5665,0,0,1,.6406-.6406h1.0879a.5666.5666,0,0,1,.64.6406v1.6a8.5461,8.5461,0,0,0,2.752,6.6563,10.5361,10.5361,0,0,0,7.36,2.4961,9.8741,9.8741,0,0,0,6.9766-2.3682,8.2188,8.2188,0,0,0,2.56-6.3359,8.3952,8.3952,0,0,0-1.12-4.416,11.3752,11.3752,0,0,0-3.3281-3.3926,71.6866,71.6866,0,0,0-6.1758-3.7119,71.0151,71.0151,0,0,1-6.24-3.84,12.1824,12.1824,0,0,1-3.4238-3.68,10.2659,10.2659,0,0,1-1.28-5.3437,9.86,9.86,0,0,1,3.0723-7.7441,12.0126,12.0126,0,0,1,8.3193-2.752q5.6969,0,8.9609,3.1035a10.8247,10.8247,0,0,1,3.2637,8.2246v1.6a.5658.5658,0,0,1-.6406.64h-1.1514a.5651.5651,0,0,1-.64-.64V56.8076a8.8643,8.8643,0,0,0-2.6241-6.6885,9.9936,9.9936,0,0,0-7.2324-2.5274,9.37,9.37,0,0,0-6.5283,2.1436,7.8253,7.8253,0,0,0-2.3672,6.1123,7.8088,7.8088,0,0,0,1.0235,4.16,10.3978,10.3978,0,0,0,3.0078,3.039,63.0249,63.0249,0,0,0,5.9521,3.4883,70.7955,70.7955,0,0,1,6.72,4.2559,13.4613,13.4613,0,0,1,3.6485,3.9365,10.044,10.044,0,0,1,1.28,5.1836,10.7185,10.7185,0,0,1-3.2647,8.1924q-3.2637,3.0717-8.832,3.0722Q516.2342,91.1757,512.8753,88.1035Z"/>
</g>
<g style="fill:currentColor;">
<g>
<path d="M99.367,36.0577l-39-22.5167a12,12,0,0,0-12,0l-39,22.5166a12.0337,12.0337,0,0,0-6,10.3924V91.4833a12.0331,12.0331,0,0,0,6,10.3923l39,22.5167a12,12,0,0,0,12,0l39-22.5167a12.0333,12.0333,0,0,0,6-10.3923V46.45A12.0336,12.0336,0,0,0,99.367,36.0577Zm-2,55.4256a4,4,0,0,1-2,3.4641l-39,22.5167a4.0006,4.0006,0,0,1-4,0l-39-22.5167a4,4,0,0,1-2-3.4641V46.45a4,4,0,0,1,2-3.4642l39-22.5166a4,4,0,0,1,4,0l39,22.5166a4,4,0,0,1,2,3.4642Z"/>
<path d="M77.3886,82.0046h-2.866a4.0007,4.0007,0,0,0-1.9247.4934L55.3172,91.9833,35.367,80.4648V57.4872l19.95-11.5185L72.606,55.4236a3.9993,3.9993,0,0,0,1.9192.4906h2.8632a2,2,0,0,0,2-2V51.2024a2,2,0,0,0-1.04-1.7547L59.16,38.9521a8.0389,8.0389,0,0,0-7.8427.09L31.3665,50.56a8.0245,8.0245,0,0,0-3.9995,6.9287v22.976a8,8,0,0,0,4,6.9283l19.95,11.5186a8.0427,8.0427,0,0,0,7.8432.0879l19.19-10.5312a2,2,0,0,0,1.0378-1.7533v-2.71A2,2,0,0,0,77.3886,82.0046Z"/>
</g>
<g>
<path d="M172.1117,45.3618a15.0166,15.0166,0,0,0-15,14.9995V77.6387a15,15,0,0,0,30,0V60.3613A15.0167,15.0167,0,0,0,172.1117,45.3618Zm7,32.2769a7,7,0,0,1-14,0V60.3613a7,7,0,0,1,14,0Z"/>
<path d="M135.4458,53.4211a7.01,7.01,0,0,1,7.8681,6.0752.9892.9892,0,0,0,.9842.865h6.03a1.0108,1.0108,0,0,0,.9987-1.0971,15.0182,15.0182,0,0,0-15.7161-13.8837A15.2881,15.2881,0,0,0,121.367,60.7968V77.2037A15.288,15.288,0,0,0,135.6112,92.62a15.0182,15.0182,0,0,0,15.7161-13.8842,1.0107,1.0107,0,0,0-.9987-1.0971h-6.03a.9892.9892,0,0,0-.9842.865,7.0106,7.0106,0,0,1-7.868,6.0757,7.1642,7.1642,0,0,1-6.0789-7.1849V60.6057A7.1638,7.1638,0,0,1,135.4458,53.4211Z"/>
<path d="M218.2891,72.9277a12.1584,12.1584,0,0,0,7.1843-11.0771V58.1494A12.1494,12.1494,0,0,0,213.324,46H196.367a1,1,0,0,0-1,1V91a1,1,0,0,0,1,1h6a1,1,0,0,0,1-1V74h6.6215l7.9154,17.4138a1,1,0,0,0,.91.5862h6.5912a1,1,0,0,0,.91-1.4138Zm-.8157-11.0771A4.1538,4.1538,0,0,1,213.3245,66h-9.8511V54h9.8511a4.1538,4.1538,0,0,1,4.1489,4.1494Z"/>
<path d="M260.367,46h-26a1,1,0,0,0-1,1V91a1,1,0,0,0,1,1h26a1,1,0,0,0,1-1V85a1,1,0,0,0-1-1h-19V72h13a1,1,0,0,0,1-1V65a1,1,0,0,0-1-1h-13V54h19a1,1,0,0,0,1-1V47A1,1,0,0,0,260.367,46Z"/>
<path d="M298.367,46h-6a1,1,0,0,0-1,1V69.6475a7.0066,7.0066,0,1,1-14,0V47a1,1,0,0,0-1-1h-6a1,1,0,0,0-1,1V69.6475a15.0031,15.0031,0,1,0,30,0V47A1,1,0,0,0,298.367,46Z"/>
<rect x="307.367" y="46" width="8" height="38" rx="1"/>
</g>
</g>
</g>
`]

BIN
src/assets/logo.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 49 KiB

View File

@@ -0,0 +1 @@
// Here you can add other styles

View File

@@ -0,0 +1 @@
// Variable overrides

View File

@@ -0,0 +1,17 @@
// If you want to override variables do it here
@import "variables";
// Import styles
@import "~@coreui/coreui/scss/coreui";
// If you want to add something do it here
@import "custom";
.card-header:not(.content-center) > .c-icon:first-child {
margin-right: 0.1rem;
margin-top: 0.1rem;
vertical-align: top;
width: 1.2rem;
height: 1.2rem;
font-size: 1.2rem;
}

View File

@@ -0,0 +1,77 @@
<template>
<CRow>
<CCol col="3">
<CSwitch
shape="pill"
class="pt-2"
label-off="Off"
label-on="On"
color="primary"
:checked="active && status"
@update:checked="updatePlanet"
:disabled="disabled"
/>
</CCol>
<CCol>
<CRow
:class="subLabel && subLabel.length > 0 ? 'mt-1' : 'mt-2'"
:style="rowStyle"
>
<CCol>
<strong
><label>{{ label }}</label></strong
>
</CCol>
</CRow>
<CRow>
<CCol style="line-height: 12px; margin-top: 5px">
<span style="font-size: 10px; opacity: 0.8">{{ subLabel }}</span>
</CCol>
</CRow>
</CCol>
</CRow>
</template>
<script>
export default {
name: 'PlanetSwitch',
props: {
label: String,
subLabel: String,
planet: Object,
active: Boolean,
disabled: Boolean,
},
computed: {
rowStyle() {
return this.subLabel && this.subLabel.length > 0
? { height: '15px' }
: {};
},
},
methods: {
updatePlanet() {
this.status = !this.status;
this.$store.dispatch('settings/updatePlanetStatus', {
planet: this.planet.name,
status: this.status,
});
this.$emit('update', this.status);
},
},
data() {
return {
status: this.planet.active,
};
},
watch: {
active(v) {
if (this.status !== v) {
this.$store.dispatch('settings/updatePlanetStatus', {
planet: this.planet.name,
status: v,
});
}
},
},
};
</script>

View File

@@ -0,0 +1,26 @@
<template>
<CCard>
<CCardHeader>
<h3>{{ title }}</h3>
</CCardHeader>
<CCardBody>
<CRow class="mb-3" v-if="description">
<CCol>{{ description }} </CCol>
</CRow>
<slot>
<CRow>
<CCol> None... YET! </CCol>
</CRow>
</slot>
</CCardBody>
</CCard>
</template>
<script>
export default {
name: 'SettingsCard',
props: {
title: String,
description: String,
},
};
</script>

View File

@@ -0,0 +1,192 @@
<template>
<CFormGroup
v-bind="{
append,
prepend,
validFeedback,
invalidFeedback,
tooltipFeedback,
description,
wrapperClasses,
class: computedClasses,
}"
>
<template #label>
<slot name="label">
<label v-if="label" :for="safeId" :class="labelClasses">
{{ label }}
</label>
</slot>
</template>
<template #input>
<input
v-bind="$attrs"
v-on="listeners"
v-integer-only
:id="safeId"
:type="type"
:class="inputClasses"
:readonly="readonly || plaintext"
:value="state"
@input="onInput($event)"
@change="onChange($event)"
/>
<div class="sub-text">{{ verbalTime }}</div>
</template>
<template v-for="slot in $options.slots" #[slot]>
<slot :name="slot"></slot>
</template>
</CFormGroup>
</template>
<style lang="scss">
.sub-text {
font-style: italic;
font-size: 9px;
font-weight: bold;
margin-top: 2px;
opacity: 0.8;
}
</style>
<script>
import * as allFormMixins from './form-mixins';
import { inputProps as props } from './form-props';
const mixins = Object.values(allFormMixins);
export default {
name: 'TimerInput',
slots: [
'prepend',
'prepend-content',
'append-content',
'append',
'label-after-input',
'valid-feedback',
'invalid-feedback',
'description',
],
inheritAttrs: false,
mixins,
props: {
...props,
unit: {
type: String,
default: 'minutes',
},
},
computed: {
listeners() {
const { input, change, ...listeners } = this.$listeners; // eslint-disable-line no-unused-vars
return listeners;
},
verbalTime() {
switch (this.unit) {
case 'seconds':
return (
this.dayValue +
' days, ' +
this.hourValue +
' hours, ' +
this.minuteValue +
' minutes and ' +
this.secondValue +
' seconds'
);
case 'minutes':
return (
this.dayValue +
' days, ' +
this.hourValue +
' hours and ' +
this.minuteValue +
' minutes'
);
case 'hours':
return this.dayValue + ' days and ' + this.hourValue + ' hours';
case 'days':
return this.dayValue + ' days';
}
},
},
methods: {
onInput(e) {
this.state = e.target.value;
this.$emit('input', this.state, e);
if (this.lazy === true) {
return;
}
clearTimeout(this.syncTimeout);
this.syncTimeout = setTimeout(
() => {
this.$emit('update:value', this.state, e);
},
this.lazy !== false ? this.lazy : 0
);
},
onChange(e) {
this.state = e.target.value;
this.$emit('change', this.state, e);
this.$emit('update:value', this.state, e);
},
},
data() {
let convertedTime = 0;
let v = this.value;
switch (this.unit) {
case 'seconds':
convertedTime = v * 1000;
break;
case 'minutes':
convertedTime = v * 1000 * 60;
break;
case 'hours':
convertedTime = v * 1000 * 60 * 60;
break;
case 'days':
convertedTime = v * 1000 * 60 * 60 * 24;
}
let base = new Date(0);
let elapsed = new Date(convertedTime);
let days = Math.floor((elapsed - base) / (1000 * 60 * 60 * 24));
let hours = elapsed.getUTCHours();
let minutes = elapsed.getUTCMinutes();
let seconds = elapsed.getUTCSeconds();
return {
dayValue: days,
hourValue: hours,
minuteValue: minutes,
secondValue: seconds,
state: this.value,
syncTimeout: null,
};
},
watch: {
state(v) {
let convertedTime = 0;
switch (this.unit) {
case 'seconds':
convertedTime = v * 1000;
break;
case 'minutes':
convertedTime = v * 1000 * 60;
break;
case 'hours':
convertedTime = v * 1000 * 60 * 60;
break;
case 'days':
convertedTime = v * 1000 * 60 * 60 * 24;
}
let base = new Date(0);
let elapsed = new Date(convertedTime);
this.dayValue = Math.floor((elapsed - base) / (1000 * 60 * 60 * 24));
this.hourValue = elapsed.getUTCHours();
this.minuteValue = elapsed.getUTCMinutes();
this.secondValue = elapsed.getUTCSeconds();
},
},
};
</script>

47
src/components/Toggle.vue Normal file
View File

@@ -0,0 +1,47 @@
<template>
<div style="margin-top: 5px">
<CRow>
<CCol>
<label
class="mr-4 switch-label"
style="vertical-align: top; margin-top: 3px"
>
{{ label }}
</label>
</CCol>
<CCol :class="{ 'text-right': alignRight }">
<CSwitch
style="width: 47px"
shape="pill"
color="primary"
label-on="On"
label-off="Off"
:checked="checked"
@update:checked="
(e) => {
$emit('update:checked', { property, value: inverse ? !e : e });
}
"
/>
</CCol>
</CRow>
</div>
</template>
<script>
export default {
name: 'Toggle',
props: {
label: String,
checked: Boolean,
property: String,
inverse: {
type: Boolean,
default: false,
},
alignRight: {
type: Boolean,
default: false,
},
},
};
</script>

View File

@@ -0,0 +1,108 @@
import { makeUid } from '@coreui/utils/src';
export const sharedComputedProps = {
computed: {
computedIsValid() {
if (typeof this.isValid === 'function') {
return this.isValid(this.state);
}
return this.isValid;
},
validationClass() {
if (typeof this.computedIsValid === 'boolean') {
return this.computedIsValid ? 'is-valid' : 'is-invalid';
}
},
safeId() {
if (this.id || this.$attrs.id) {
return this.id || this.$attrs.id;
}
return makeUid();
},
},
};
export const wrapperComputedProps = {
computed: {
isHorizontal() {
return Boolean(this.horizontal);
},
haveInputGroup() {
return Boolean(
this.tooltipFeedback ||
this.append ||
this.prepend ||
this.$slots.append ||
this.$slots.prepend ||
this.$slots['append-content'] ||
this.$slots['prepend-content']
);
},
haveWrapper() {
return (
this.haveInputGroup ||
Boolean(this.addWrapperClasses || this.isHorizontal)
);
},
wrapperClasses() {
if (this.haveWrapper) {
return [
this.addWrapperClasses,
{
[this.horizontal.input || 'col-sm-9']: this.isHorizontal,
'input-group': this.haveInputGroup,
[`input-group-${this.size}`]: this.haveCustomSize,
},
];
}
},
},
};
export const watchValue = {
watch: {
value(val) {
this.state = val;
},
},
};
export const classesComputedProps = {
computed: {
haveCustomSize() {
return ['sm', 'lg'].includes(this.size);
},
computedClasses() {
return [
'form-group',
{
'was-validated': this.wasValidated,
'form-row': this.isHorizontal,
},
];
},
labelClasses() {
return [
this.addLabelClasses,
{
'col-form-label': this.isHorizontal,
[this.horizontal.label || 'col-sm-3']: this.isHorizontal,
[`col-form-label-${this.size}`]: this.haveCustomSize,
},
];
},
customSizeClass() {
if (this.haveCustomSize && !this.haveWrapper) {
return `form-control-${this.size}`;
}
},
inputClasses() {
return [
this.inputClass || `form-control${this.plaintext ? '-plaintext' : ''}`,
this.validationClass,
this.addInputClasses,
this.customSizeClass,
];
},
},
};

View File

@@ -0,0 +1,108 @@
const formGroupAlwaysSharedProps = {
validFeedback: String,
invalidFeedback: String,
tooltipFeedback: Boolean,
description: String
}
const formGroupSharedProps = Object.assign(
{},
formGroupAlwaysSharedProps,
{
append: String,
prepend: String
}
)
export const formGroupProps = Object.assign(
{}, formGroupSharedProps, { wrapperClasses: [String, Array, Object] }
)
const universalProps = {
label: String,
wasValidated: Boolean,
isValid: {
type: [Boolean, Function],
default: null
},
addInputClasses: [String, Array, Object],
addLabelClasses: [String, Array, Object]
}
const props = Object.assign(
{},
universalProps,
{
horizontal: [Boolean, Object],
size: {
type: String,
validator: str => ['','sm','lg'].includes(str)
},
addWrapperClasses: [String, Array, Object]
}
)
const textInputsProps = {
readonly: Boolean,
plaintext: Boolean,
value: [String, Number],
lazy: {
type: [Boolean, Number],
default: 400
}
}
// Html props: disabled, required, accept, id, placeholder
export const inputFileProps = Object.assign(
{},
formGroupAlwaysSharedProps,
props,
{
custom: Boolean,
placeholder: String,
multiple: Boolean
}
)
// Html props: disabled, required, rows, cols, placeholder, id
export const textareaProps = Object.assign(
{}, formGroupSharedProps, props, textInputsProps
)
// HTML props: disabled, required, placeholder, id
export const inputProps = Object.assign(
{},
formGroupSharedProps,
props,
textInputsProps,
{
type: {
type: String,
default: 'text'
}
}
)
// Html props: disabled, id required don't use multiple
export const selectProps = Object.assign(
{},
formGroupSharedProps,
props,
{
options: Array,
value: [String, Number, Boolean, Array],
plaintext: Boolean,
placeholder: String,
custom: Boolean
}
)
// Html props: id, disabled, required
export const inputCheckboxProps = Object.assign(
{},
formGroupAlwaysSharedProps,
universalProps,
{
checked: Boolean,
custom: Boolean,
inline: Boolean
}
)

View File

@@ -0,0 +1,41 @@
<template>
<div class="c-app">
<TheSidebar/>
<CWrapper>
<TheHeader/>
<div class="c-body">
<main class="c-main">
<CContainer fluid>
<transition name="fade" mode="out-in">
<router-view :key="$route.path"></router-view>
</transition>
</CContainer>
</main>
</div>
</CWrapper>
</div>
</template>
<script>
import TheSidebar from './TheSidebar'
import TheHeader from './TheHeader'
export default {
name: 'TheContainer',
components: {
TheSidebar,
TheHeader
}
}
</script>
<style scoped>
.fade-enter-active,
.fade-leave-active {
transition: opacity 0.3s;
}
.fade-enter,
.fade-leave-to {
opacity: 0;
}
</style>

View File

@@ -0,0 +1,32 @@
<template>
<CHeader fixed with-subheader light>
<CToggler
in-header
class="ml-3 d-lg-none"
@click="$store.commit('toggleSidebarMobile')"
/>
<CToggler
in-header
class="ml-3 d-md-down-none"
@click="$store.commit('toggleSidebarDesktop')"
/>
<CHeaderBrand class="mx-auto d-lg-none" to="/">
<CIcon name="logo" height="48" alt="Logo" />
</CHeaderBrand>
<CHeaderNav class="d-md-down-none mr-auto" />
<CSubheader class="px-3">
<CBreadcrumbRouter class="border-0 mb-0" />
</CSubheader>
</CHeader>
</template>
<script>
export default {
name: 'TheHeader',
data() {
return {
serverStatus: false,
};
},
};
</script>

View File

@@ -0,0 +1,35 @@
<template>
<CSidebar
fixed
:minimize="minimize"
:show="show"
@update:show="(value) => $store.commit('set', ['sidebarShow', value])"
>
<CSidebarBrand class="d-md-down-none" to="/">
<img src="@/assets/logo.png" height="40" class="mr-2"/><strong>Source SMC</strong>
</CSidebarBrand>
<CRenderFunction flat :content-to-render="$options.nav"/>
<CSidebarMinimizer
class="d-md-down-none"
@click.native="$store.commit('set', ['sidebarMinimize', !minimize])"
/>
</CSidebar>
</template>
<script>
import nav from './_nav'
export default {
name: 'TheSidebar',
nav,
computed: {
show () {
return this.$store.state.sidebarShow
},
minimize () {
return this.$store.state.sidebarMinimize
}
}
}
</script>

96
src/containers/_nav.js Normal file
View File

@@ -0,0 +1,96 @@
export default [
{
_name: 'CSidebarNav',
_children: [
{
_name: 'CSidebarNavItem',
name: 'Server Dashboard',
to: '/dashboard',
icon: 'cil-speedometer',
},
{
_name: 'CSidebarNavTitle',
_children: ['Game'],
},
{
_name: 'CSidebarNavDropdown',
name: 'Resources',
icon: 'cil-terrain',
_children: [
{
_name: 'CSidebarNavItem',
name: 'Current Spawns',
to: '/resources/active',
},
{
_name: 'CSidebarNavItem',
name: 'All Spawns',
to: '/resources',
},
],
},
{
_name: 'CSidebarNavDropdown',
name: 'Commodities',
icon: 'cil-bank',
_children: [
{
_name: 'CSidebarNavItem',
name: 'Current Listings',
to: '/bazaar/active',
},
],
},
{
_name: 'CSidebarNavDropdown',
name: 'Players',
icon: 'cil-people',
_children: [
{
_name: 'CSidebarNavItem',
name: 'Active',
to: '/players',
},
],
},
{
_name: 'CSidebarNavDropdown',
name: 'Cities',
icon: 'cil-building',
_children: [
{
_name: 'CSidebarNavItem',
name: 'All',
to: '/cities',
},
],
},
{
_name: 'CSidebarNavTitle',
_children: ['Administration'],
},
{
_name: 'CSidebarNavDropdown',
name: 'Settings',
icon: 'cil-settings',
_children: [
{
_name: 'CSidebarNavItem',
name: 'Game',
to: '/admin/settings/game',
},
{
_name: 'CSidebarNavItem',
name: 'Logging',
to: '/admin/settings/logging',
},
{
_name: 'CSidebarNavItem',
name: 'Server',
to: '/admin/settings/server',
},
],
},
],
},
];

45
src/main.js Normal file
View File

@@ -0,0 +1,45 @@
import 'core-js/stable';
import Vue from 'vue';
import App from './App';
import router from './router';
import CoreuiVue from '@coreui/vue';
import { iconsSet as icons } from './assets/icons/icons.js';
import store from './store';
Vue.config.performance = true;
Vue.use(CoreuiVue);
Vue.prototype.$log = console.log.bind(console);
Vue.directive('integer-only', {
bind(el) {
el.addEventListener('keypress', (e) => {
let kc = e.keyCode || e.which;
let regex = /[0-9]/;
if (!regex.test(String.fromCharCode(kc))) {
e.preventDefault();
}
});
},
});
Vue.directive('float-only', {
bind(el) {
el.addEventListener('keypress', (e) => {
let kc = e.keyCode || e.which;
let regex = /[0-9.]/;
if (!regex.test(String.fromCharCode(kc))) {
e.preventDefault();
}
});
},
});
new Vue({
el: '#app',
router,
store,
icons,
template: '<App/>',
components: {
App,
},
});

110
src/router/index.js Normal file
View File

@@ -0,0 +1,110 @@
import Vue from 'vue';
import Router from 'vue-router';
// Containers
const TheContainer = () => import('@/containers/TheContainer');
// Views
const Dashboard = () => import('@/views/Dashboard');
const ViewCity = () => import('@/views/city/ViewCity');
const ViewPlayer = () => import('@/views/player/ViewPlayer');
const CityList = () => import('@/views/city/CityList');
// Settings
const GameSettings = () => import('@/views/settings/Game');
const LoggingSettings = () => import('@/views/settings/Logging');
const ServerSettings = () => import('@/views/settings/Server');
Vue.use(Router);
export default new Router({
mode: 'hash', // https://router.vuejs.org/api/#mode
linkActiveClass: 'active',
scrollBehavior: () => ({ y: 0 }),
routes: configRoutes(),
});
function configRoutes() {
return [
{
path: '/',
redirect: '/dashboard',
name: 'Home',
component: TheContainer,
children: [
{
path: 'dashboard',
name: 'Dashboard',
component: Dashboard,
},
{
path: 'city/:name',
name: 'view-city',
props: true,
component: ViewCity,
meta: {
label: 'City Details',
title: 'City Details',
},
},
{
path: 'cities',
name: 'city-list',
component: CityList,
meta: {
label: 'City List',
title: 'City List',
},
},
{
path: 'player/:objectId',
name: 'view-player',
props: true,
component: ViewPlayer,
meta: {
label: 'Player Details',
title: 'Player Details',
},
},
],
},
{
path: '/admin/settings',
redirect: '/dashboard',
name: 'Settings',
component: TheContainer,
children: [
{
path: 'game',
name: 'game-settings',
props: true,
component: GameSettings,
meta: {
label: 'Game',
title: 'Game',
},
},
{
path: 'logging',
name: 'logging-settings',
props: true,
component: LoggingSettings,
meta: {
label: 'Logging',
title: 'Logging',
},
},
{
path: 'server',
name: 'server-settings',
props: true,
component: ServerSettings,
meta: {
label: 'Server',
title: 'Server',
},
},
],
},
];
}

19
src/store/index.js Normal file
View File

@@ -0,0 +1,19 @@
import Vue from 'vue';
import Vuex from 'vuex';
import city from './modules/city-module';
import coreui from './modules/coreui-module';
import settings from './modules/settings-module';
Vue.use(Vuex);
const debug = true;
export default new Vuex.Store({
modules: {
city,
coreui: coreui,
settings,
},
strict: debug,
plugins: [],
});

View File

@@ -0,0 +1,35 @@
import { get, set } from './state-mutators';
import api from '@/api';
const state = {
allCities: [],
};
const getters = {
cities: get('allCities'),
};
const mutations = {
cities: set('allCities'),
};
const actions = {
fetchAll({ commit }) {
return api.city
.all()
.then((cities) => {
commit('cities', cities);
})
.catch((e) => {
console.error('Could not fetch all cities: ', { ...e });
});
},
};
export default {
namespaced: true,
state,
getters,
mutations,
actions,
};

View File

@@ -0,0 +1,27 @@
import Vue from 'vue'
import Vuex from 'vuex'
Vue.use(Vuex)
const state = {
sidebarShow: 'responsive',
sidebarMinimize: false
}
const mutations = {
toggleSidebarDesktop (state) {
const sidebarOpened = [true, 'responsive'].includes(state.sidebarShow)
state.sidebarShow = sidebarOpened ? false : 'responsive'
},
toggleSidebarMobile (state) {
const sidebarClosed = [false, 'responsive'].includes(state.sidebarShow)
state.sidebarShow = sidebarClosed ? true : 'responsive'
},
set (state, [variable, value]) {
state[variable] = value
}
}
export default new Vuex.Store({
state,
mutations
})

View File

@@ -0,0 +1,50 @@
import { get, set } from './state-mutators';
import api from '@/api';
const state = {
allSettings: [],
};
const getters = {
settings: get('allSettings'),
};
const mutations = {
settings: set('allSettings'),
updatePlanetStatus(state, planet) {
state.allSettings.centralServer.startPlanet.find(
(p) => p.name === planet.planet
).active = planet.status;
},
updateProperty(state, { property, value }) {
let tree = property.split('.');
state.allSettings[tree[0]][tree[1]] = value;
},
};
const actions = {
fetchAll({ commit }) {
return api.settings
.all()
.then((settings) => {
commit('settings', settings);
})
.catch((e) => {
console.error('Could not fetch all settings: ', { ...e });
});
},
updatePlanetStatus({ commit }, { planet, status }) {
commit('updatePlanetStatus', { planet, status });
},
updateProperty({ commit }, { property, value }) {
commit('updateProperty', { property, value });
},
};
export default {
namespaced: true,
state,
getters,
mutations,
actions,
};

View File

@@ -0,0 +1,21 @@
import _ from 'lodash';
/**
* Reusable generic property getter
* @param {String} propName
* @returns {*} The value of state[propName]
*/
export const get = (propName) => (state) => {
return _.get(state, propName);
};
/**
* Reusable generic property setter
* @param {String} propName
* @param {Object} value
* @returns void
*/
export const set = (propName) => (state, value) => {
_.set(state, propName, value);
};

522
src/views/Dashboard.vue Normal file
View File

@@ -0,0 +1,522 @@
<template>
<div>
<CCard>
<CCardBody>
<CRow>
<CCol>
<h4 id="traffic" class="card-title mb-0">
Server Status:
<CBadge
shape="pill"
class="ml-2"
:color="serverStatus ? 'success' : 'danger'"
>
{{ serverStatus ? 'RUNNING' : 'STOPPED' }}
</CBadge>
</h4>
<div class="small text-muted">
Last Session: 2 days, 14 hours, 21 minutes
</div>
</CCol>
<CCol class="text-right">
<CButton
:color="!serverStatus ? 'success' : 'danger'"
@click="startServer"
>{{ !serverStatus ? 'Start' : 'Stop' }} Server</CButton
>
</CCol>
</CRow>
</CCardBody>
</CCard>
<WidgetsDropdown />
<CCard>
<CCardBody>
<CRow>
<CCol sm="5">
<h4 id="traffic" class="card-title mb-0">
Server Population (Players)
</h4>
<div class="small text-muted">March 2021</div>
</CCol>
<CCol sm="7" class="d-none d-md-block">
<CButton color="primary" class="float-right">
<CIcon name="cil-cloud-download" />
</CButton>
<CButtonGroup class="float-right mr-3">
<CButton
color="outline-secondary"
v-for="(value, key) in ['Day', 'Month', 'Year']"
:key="key"
class="mx-0"
:pressed="value === selected ? true : false"
@click="selected = value"
>
{{ value }}
</CButton>
</CButtonGroup>
</CCol>
</CRow>
<MainChartExample style="height: 300px; margin-top: 40px" />
</CCardBody>
<CCardFooter>
<CRow class="text-center">
<CCol md sm="12" class="mb-sm-2 mb-0">
<div class="text-muted">Jedi</div>
<strong>29.703 Characters (40%)</strong>
<CProgress
class="progress-xs mt-2"
:precision="1"
color="success"
:value="40"
/>
</CCol>
<CCol md sm="12" class="mb-sm-2 mb-0 d-md-down-none">
<div class="text-muted">Trader</div>
<strong>24.093 Characters (20%)</strong>
<CProgress
class="progress-xs mt-2"
:precision="1"
color="info"
:value="20"
/>
</CCol>
<CCol md sm="12" class="mb-sm-2 mb-0">
<div class="text-muted">Smuggler</div>
<strong>78.706 Characters (40%)</strong>
<CProgress
class="progress-xs mt-2"
:precision="1"
color="warning"
:value="60"
/>
</CCol>
<CCol md sm="12" class="mb-sm-2 mb-0">
<div class="text-muted">Commando</div>
<strong>22.123 Characters (20%)</strong>
<CProgress
class="progress-xs mt-2"
:precision="1"
color="danger"
:value="80"
/>
</CCol>
<CCol md sm="12" class="mb-sm-2 mb-0 d-md-down-none">
<div class="text-muted">Bounty Hunter</div>
<strong>12,209 Characters (30%)</strong>
<CProgress class="progress-xs mt-2" :precision="1" :value="40" />
</CCol>
</CRow>
</CCardFooter>
</CCard>
<CRow>
<CCol md="12">
<CCard>
<CCardHeader> Traffic &amp; Sales </CCardHeader>
<CCardBody>
<CRow>
<CCol sm="12" lg="6">
<CRow>
<CCol sm="6">
<CCallout color="info">
<small class="text-muted">New Clients</small><br />
<strong class="h4">9,123</strong>
</CCallout>
</CCol>
<CCol sm="6">
<CCallout color="danger">
<small class="text-muted">Recurring Clients</small><br />
<strong class="h4">22,643</strong>
</CCallout>
</CCol>
</CRow>
<hr class="mt-0" />
<div class="progress-group mb-4">
<div class="progress-group-prepend">
<span class="progress-group-text"> Monday </span>
</div>
<div class="progress-group-bars">
<CProgress class="progress-xs" color="info" :value="34" />
<CProgress class="progress-xs" color="danger" :value="78" />
</div>
</div>
<div class="progress-group mb-4">
<div class="progress-group-prepend">
<span class="progress-group-text"> Tuesday </span>
</div>
<div class="progress-group-bars">
<CProgress class="progress-xs" :value="56" color="info" />
<CProgress class="progress-xs" :value="94" color="danger" />
</div>
</div>
<div class="progress-group mb-4">
<div class="progress-group-prepend">
<span class="progress-group-text"> Wednesday </span>
</div>
<div class="progress-group-bars">
<CProgress class="progress-xs" :value="12" color="info" />
<CProgress class="progress-xs" :value="67" color="danger" />
</div>
</div>
<div class="progress-group mb-4">
<div class="progress-group-prepend">
<span class="progress-group-text"> Thursday </span>
</div>
<div class="progress-group-bars">
<CProgress class="progress-xs" :value="43" color="info" />
<CProgress class="progress-xs" :value="91" color="danger" />
</div>
</div>
<div class="progress-group mb-4">
<div class="progress-group-prepend">
<span class="progress-group-text"> Friday </span>
</div>
<div class="progress-group-bars">
<CProgress class="progress-xs" :value="22" color="info" />
<CProgress class="progress-xs" :value="73" color="danger" />
</div>
</div>
<div class="progress-group mb-4">
<div class="progress-group-prepend">
<span class="progress-group-text"> Saturday </span>
</div>
<div class="progress-group-bars">
<CProgress class="progress-xs" :value="53" color="info" />
<CProgress class="progress-xs" :value="82" color="danger" />
</div>
</div>
<div class="progress-group mb-4">
<div class="progress-group-prepend">
<span class="progress-group-text"> Sunday </span>
</div>
<div class="progress-group-bars">
<CProgress class="progress-xs" :value="9" color="info" />
<CProgress class="progress-xs" :value="69" color="danger" />
</div>
</div>
<div class="legend text-center">
<small>
<sup><CBadge shape="pill" color="info">&nbsp;</CBadge></sup>
New clients &nbsp;&nbsp;
<sup
><CBadge shape="pill" color="danger">&nbsp;</CBadge></sup
>
Recurring clients
</small>
</div>
</CCol>
<CCol sm="12" lg="6">
<CRow>
<CCol sm="6">
<CCallout color="warning">
<small class="text-muted">Pageviews</small><br />
<strong class="h4">78,623</strong>
</CCallout>
</CCol>
<CCol sm="6">
<CCallout color="success">
<small class="text-muted">Organic</small><br />
<strong class="h4">49,123</strong>
</CCallout>
</CCol>
</CRow>
<hr class="mt-0" />
<ul class="horizontal-bars type-2">
<div class="progress-group">
<div class="progress-group-header">
<CIcon name="cil-user" class="progress-group-icon" />
<span class="title">Male</span>
<span class="ml-auto font-weight-bold">43%</span>
</div>
<div class="progress-group-bars">
<CProgress
class="progress-xs"
:value="43"
color="warning"
/>
</div>
</div>
<div class="progress-group mb-5">
<div class="progress-group-header">
<CIcon
name="cil-user-female"
class="progress-group-icon"
/>
<span class="title">Female</span>
<span class="ml-auto font-weight-bold">37%</span>
</div>
<div class="progress-group-bars">
<CProgress
class="progress-xs"
:value="37"
color="warning"
/>
</div>
</div>
<div class="progress-group">
<div class="progress-group-header">
<CIcon name="cil-globe-alt" class="progress-group-icon" />
<span class="title">Organic Search</span>
<span class="ml-auto font-weight-bold">
191,235 <span class="text-muted small">(56%)</span>
</span>
</div>
<div class="progress-group-bars">
<CProgress
class="progress-xs"
:value="56"
color="success"
/>
</div>
</div>
<div class="progress-group">
<div class="progress-group-header">
<CIcon
name="cib-facebook"
height="17"
class="progress-group-icon"
/>
<span class="title">Facebook</span>
<span class="ml-auto font-weight-bold">
51,223 <span class="text-muted small">(15%)</span>
</span>
</div>
<div class="progress-group-bars">
<CProgress
class="progress-xs"
:value="15"
color="success"
/>
</div>
</div>
<div class="progress-group">
<div class="progress-group-header">
<CIcon
name="cib-twitter"
height="17"
class="progress-group-icon"
/>
<span class="title">Twitter</span>
<span class="ml-auto font-weight-bold">
37,564 <span class="text-muted small">(11%)</span>
</span>
</div>
<div class="progress-group-bars">
<CProgress
class="progress-xs"
:value="11"
color="success"
/>
</div>
</div>
<div class="progress-group">
<div class="progress-group-header">
<CIcon
name="cib-linkedin"
height="17"
class="progress-group-icon"
/>
<span class="title">LinkedIn</span>
<span class="ml-auto font-weight-bold">
27,319 <span class="text-muted small">&nbsp;(8%)</span>
</span>
</div>
<div class="progress-group-bars">
<CProgress
class="progress-xs"
:value="8"
color="success"
/>
</div>
</div>
<div class="divider text-center">
<CButton color="link" size="sm" class="text-muted">
<CIcon name="cil-options" />
</CButton>
</div>
</ul>
</CCol>
</CRow>
<br />
<CDataTable
class="mb-0 table-outline"
hover
:items="tableItems"
:fields="tableFields"
head-color="light"
no-sorting
>
<td slot="avatar" class="text-center" slot-scope="{ item }">
<div class="c-avatar">
<img :src="item.avatar.url" class="c-avatar-img" alt="" />
<span
class="c-avatar-status"
:class="`bg-${item.avatar.status || 'secondary'}`"
></span>
</div>
</td>
<td slot="user" slot-scope="{ item }">
<div>{{ item.user.name }}</div>
<div class="small text-muted">
<span>
<template v-if="item.user.new">New</template>
<template v-else>Recurring</template>
</span>
| Registered: {{ item.user.registered }}
</div>
</td>
<td slot="country" slot-scope="{ item }" class="text-center">
<CIcon :name="item.country.flag" height="25" />
</td>
<td slot="usage" slot-scope="{ item }">
<div class="clearfix">
<div class="float-left">
<strong>{{ item.usage.value }}%</strong>
</div>
<div class="float-right">
<small class="text-muted">{{ item.usage.period }}</small>
</div>
</div>
<CProgress
class="progress-xs"
v-model="item.usage.value"
:color="color(item.usage.value)"
/>
</td>
<td slot="payment" slot-scope="{ item }" class="text-center">
<CIcon :name="item.payment.icon" height="25" />
</td>
<td slot="activity" slot-scope="{ item }">
<div class="small text-muted">Last login</div>
<strong>{{ item.activity }}</strong>
</td>
</CDataTable>
</CCardBody>
</CCard>
</CCol>
</CRow>
</div>
</template>
<script>
import MainChartExample from './charts/MainChartExample';
import WidgetsDropdown from './widgets/WidgetsDropdown';
export default {
name: 'Dashboard',
components: {
MainChartExample,
WidgetsDropdown,
},
data() {
return {
serverStatus: false,
selected: 'Month',
tableItems: [
{
avatar: { url: 'img/avatars/1.jpg', status: 'success' },
user: {
name: 'Yiorgos Avraamu',
new: true,
registered: 'Jan 1, 2015',
},
country: { name: 'USA', flag: 'cif-us' },
usage: { value: 50, period: 'Jun 11, 2015 - Jul 10, 2015' },
payment: { name: 'Mastercard', icon: 'cib-cc-mastercard' },
activity: '10 sec ago',
},
{
avatar: { url: 'img/avatars/2.jpg', status: 'danger' },
user: {
name: 'Avram Tarasios',
new: false,
registered: 'Jan 1, 2015',
},
country: { name: 'Brazil', flag: 'cif-br' },
usage: { value: 22, period: 'Jun 11, 2015 - Jul 10, 2015' },
payment: { name: 'Visa', icon: 'cib-cc-visa' },
activity: '5 minutes ago',
},
{
avatar: { url: 'img/avatars/3.jpg', status: 'warning' },
user: {
name: 'Quintin Ed',
new: true,
registered: 'Jan 1, 2015',
},
country: { name: 'India', flag: 'cif-in' },
usage: { value: 74, period: 'Jun 11, 2015 - Jul 10, 2015' },
payment: { name: 'Stripe', icon: 'cib-stripe' },
activity: '1 hour ago',
},
{
avatar: { url: 'img/avatars/4.jpg', status: '' },
user: {
name: 'Enéas Kwadwo',
new: true,
registered: 'Jan 1, 2015',
},
country: { name: 'France', flag: 'cif-fr' },
usage: { value: 98, period: 'Jun 11, 2015 - Jul 10, 2015' },
payment: { name: 'PayPal', icon: 'cib-paypal' },
activity: 'Last month',
},
{
avatar: { url: 'img/avatars/5.jpg', status: 'success' },
user: {
name: 'Agapetus Tadeáš',
new: true,
registered: 'Jan 1, 2015',
},
country: { name: 'Spain', flag: 'cif-es' },
usage: { value: 22, period: 'Jun 11, 2015 - Jul 10, 2015' },
payment: { name: 'Google Wallet', icon: 'cib-google-pay' },
activity: 'Last week',
},
{
avatar: { url: 'img/avatars/6.jpg', status: 'danger' },
user: {
name: 'Friderik Dávid',
new: true,
registered: 'Jan 1, 2015',
},
country: { name: 'Poland', flag: 'cif-pl' },
usage: { value: 43, period: 'Jun 11, 2015 - Jul 10, 2015' },
payment: { name: 'Amex', icon: 'cib-cc-amex' },
activity: 'Last week',
},
],
tableFields: [
{ key: 'avatar', label: '', _classes: 'text-center' },
{ key: 'user' },
{ key: 'country', _classes: 'text-center' },
{ key: 'usage' },
{
key: 'payment',
label: 'Payment method',
_classes: 'text-center',
},
{ key: 'activity' },
],
};
},
methods: {
color(value) {
let $color;
if (value <= 25) {
$color = 'info';
} else if (value > 25 && value <= 50) {
$color = 'success';
} else if (value > 50 && value <= 75) {
$color = 'warning';
} else if (value > 75 && value <= 100) {
$color = 'danger';
}
return $color;
},
startServer() {
if (serverStatus) return;
console.log('starting server');
},
},
};
</script>

View File

@@ -0,0 +1,26 @@
<template>
<CChartBar
:datasets="defaultDatasets"
labels="months"
/>
</template>
<script>
import { CChartBar } from '@coreui/vue-chartjs'
export default {
name: 'CChartBarExample',
components: { CChartBar },
computed: {
defaultDatasets () {
return [
{
label: 'GitHub Commits',
backgroundColor: '#f87979',
data: [40, 20, 12, 39, 10, 40, 39, 80, 40, 20, 12, 11]
}
]
}
}
}
</script>

View File

@@ -0,0 +1,70 @@
<template>
<CChartBar
:datasets="computedDatasets"
:options="computedOptions"
:labels="labels"
/>
</template>
<script>
import { CChartBar } from '@coreui/vue-chartjs'
import { getColor, deepObjectsMerge } from '@coreui/utils/src'
export default {
name: 'CChartBarSimple',
components: { CChartBar },
props: {
...CChartBar.props,
backgroundColor: {
type: String,
default: 'rgba(0,0,0,.2)'
},
pointHoverBackgroundColor: String,
dataPoints: {
type: Array,
default: () => [10, 22, 34, 46, 58, 70, 46, 23, 45, 78, 34, 12]
},
label: {
type: String,
default: 'Sales'
},
pointed: Boolean
},
computed: {
defaultDatasets () {
return [
{
data: this.dataPoints,
backgroundColor: getColor(this.backgroundColor),
pointHoverBackgroundColor: getColor(this.pointHoverBackgroundColor),
label: this.label,
barPercentage: 0.5,
categoryPercentage: 1
}
]
},
defaultOptions () {
return {
maintainAspectRatio: false,
legend: {
display: false
},
scales: {
xAxes: [{
display: false
}],
yAxes: [{
display: false
}]
}
}
},
computedDatasets () {
return deepObjectsMerge(this.defaultDatasets, this.datasets || {})
},
computedOptions () {
return deepObjectsMerge(this.defaultOptions, this.options || {})
}
}
}
</script>

View File

@@ -0,0 +1,30 @@
<template>
<CChartDoughnut
:datasets="defaultDatasets"
:labels="['VueJs', 'EmberJs', 'ReactJs', 'AngularJs']"
/>
</template>
<script>
import { CChartDoughnut } from '@coreui/vue-chartjs'
export default {
name: 'CChartDoughnutExample',
components: { CChartDoughnut },
computed: {
defaultDatasets () {
return [
{
backgroundColor: [
'#41B883',
'#E46651',
'#00D8FF',
'#DD1B16'
],
data: [40, 20, 80, 10]
}
]
}
}
}
</script>

View File

@@ -0,0 +1,31 @@
<template>
<CChartLine
:datasets="defaultDatasets"
labels="months"
/>
</template>
<script>
import { CChartLine } from '@coreui/vue-chartjs'
export default {
name: 'CChartLineExample',
components: { CChartLine },
computed: {
defaultDatasets () {
return [
{
label: 'Data One',
backgroundColor: 'rgb(228,102,81,0.9)',
data: [30, 39, 10, 50, 30, 70, 35]
},
{
label: 'Data Two',
backgroundColor: 'rgb(0,216,255,0.9)',
data: [39, 80, 40, 35, 40, 20, 45]
}
]
}
}
}
</script>

View File

@@ -0,0 +1,136 @@
<template>
<CChartLine
:datasets="computedDatasets"
:options="computedOptions"
:labels="labels"
/>
</template>
<script>
import { CChartLine } from '@coreui/vue-chartjs'
import { getColor, deepObjectsMerge } from '@coreui/utils/src'
export default {
name: 'CChartLineSimple',
components: { CChartLine },
props: {
...CChartLine.props,
borderColor: {
type: String,
default: 'rgba(255,255,255,.55)'
},
backgroundColor: {
type: String,
default: 'transparent'
},
dataPoints: {
type: Array,
default: () => [10, 22, 34, 46, 58, 70, 46, 23, 45, 78, 34, 12]
},
label: {
type: String,
default: 'Sales'
},
pointed: Boolean,
pointHoverBackgroundColor: String
},
computed: {
pointHoverColor () {
if (this.pointHoverBackgroundColor) {
return this.pointHoverBackgroundColor
} else if (this.backgroundColor !== 'transparent') {
return this.backgroundColor
}
return this.borderColor
},
defaultDatasets () {
return [
{
data: this.dataPoints,
borderColor: getColor(this.borderColor),
backgroundColor: getColor(this.backgroundColor),
pointBackgroundColor: getColor(this.pointHoverColor),
pointHoverBackgroundColor: getColor(this.pointHoverColor),
label: this.label
}
]
},
pointedOptions () {
return {
scales: {
xAxes: [
{
offset: true,
gridLines: {
color: 'transparent',
zeroLineColor: 'transparent'
},
ticks: {
fontSize: 2,
fontColor: 'transparent'
}
}
],
yAxes: [
{
display: false,
ticks: {
display: false,
min: Math.min.apply(Math, this.dataPoints) - 5,
max: Math.max.apply(Math, this.dataPoints) + 5
}
}
]
},
elements: {
line: {
borderWidth: 1
},
point: {
radius: 4,
hitRadius: 10,
hoverRadius: 4
}
}
}
},
straightOptions () {
return {
scales: {
xAxes: [{
display: false
}],
yAxes: [{
display: false
}]
},
elements: {
line: {
borderWidth: 2
},
point: {
radius: 0,
hitRadius: 10,
hoverRadius: 4
}
}
}
},
defaultOptions () {
const options = this.pointed ? this.pointedOptions : this.straightOptions
return Object.assign({}, options, {
maintainAspectRatio: false,
legend: {
display: false
}
})
},
computedDatasets () {
return deepObjectsMerge(this.defaultDatasets, this.datasets || {})
},
computedOptions () {
return deepObjectsMerge(this.defaultOptions, this.options || {})
}
}
}
</script>

View File

@@ -0,0 +1,30 @@
<template>
<CChartPie
:datasets="defaultDatasets"
:labels="['VueJs', 'EmberJs', 'ReactJs', 'AngularJs']"
/>
</template>
<script>
import { CChartPie } from '@coreui/vue-chartjs'
export default {
name: 'CChartPieExample',
components: { CChartPie },
computed: {
defaultDatasets () {
return [
{
backgroundColor: [
'#41B883',
'#E46651',
'#00D8FF',
'#DD1B16'
],
data: [40, 20, 80, 10]
}
]
}
}
}
</script>

View File

@@ -0,0 +1,48 @@
<template>
<CChartPolarArea
:datasets="defaultDatasets"
:options="defaultOptions"
:labels="[
'Eating', 'Drinking', 'Sleeping', 'Designing',
'Coding', 'Cycling', 'Running'
]"
/>
</template>
<script>
import { CChartPolarArea } from '@coreui/vue-chartjs'
export default {
name: 'CChartPolarAreaExample',
components: { CChartPolarArea },
computed: {
defaultDatasets () {
return [
{
label: 'My First dataset',
backgroundColor: 'rgba(179,181,198,0.2)',
pointBackgroundColor: 'rgba(179,181,198,1)',
pointBorderColor: '#fff',
pointHoverBackgroundColor: 'rgba(179,181,198,1)',
pointHoverBorderColor: 'rgba(179,181,198,1)',
data: [65, 59, 90, 81, 56, 55, 40]
},
{
label: 'My Second dataset',
backgroundColor: 'rgba(255,99,132,0.2)',
pointBackgroundColor: 'rgba(255,99,132,1)',
pointBorderColor: '#fff',
pointHoverBackgroundColor: 'rgba(255,99,132,1)',
pointHoverBorderColor: 'rgba(255,99,132,1)',
data: [28, 48, 40, 19, 96, 27, 100]
}
]
},
defaultOptions () {
return {
aspectRatio: 1.5
}
}
}
}
</script>

View File

@@ -0,0 +1,52 @@
<template>
<CChartRadar
:datasets="defaultDatasets"
:options="defaultOptions"
:labels="[
'Eating', 'Drinking', 'Sleeping', 'Designing',
'Coding', 'Cycling', 'Running'
]"
/>
</template>
<script>
import { CChartRadar } from '@coreui/vue-chartjs'
export default {
name: 'CChartRadarExample',
components: { CChartRadar },
computed: {
defaultDatasets () {
return [
{
label: '2019',
backgroundColor: 'rgba(179,181,198,0.2)',
borderColor: 'rgba(179,181,198,1)',
pointBackgroundColor: 'rgba(179,181,198,1)',
pointBorderColor: '#fff',
pointHoverBackgroundColor: '#fff',
pointHoverBorderColor: 'rgba(179,181,198,1)',
tooltipLabelColor: 'rgba(179,181,198,1)',
data: [65, 59, 90, 81, 56, 55, 40]
},
{
label: '2020',
backgroundColor: 'rgba(255,99,132,0.2)',
borderColor: 'rgba(255,99,132,1)',
pointBackgroundColor: 'rgba(255,99,132,1)',
pointBorderColor: '#fff',
pointHoverBackgroundColor: '#fff',
pointHoverBorderColor: 'rgba(255,99,132,1)',
tooltipLabelColor: 'rgba(255,99,132,1)',
data: [28, 48, 40, 19, 96, 27, 100]
}
]
},
defaultOptions () {
return {
aspectRatio: 1.5
}
}
}
}
</script>

View File

@@ -0,0 +1,68 @@
<template>
<div>
<CCardGroup columns class="card-columns cols-2">
<CCard>
<CCardHeader>
Line Chart
<div class="card-header-actions">
<a
href="https://coreui.io/vue/docs/components/charts"
class="card-header-action"
rel="noreferrer noopener"
target="_blank"
>
<small class="text-muted">docs</small>
</a>
</div>
</CCardHeader>
<CCardBody>
<CChartLineExample/>
</CCardBody>
</CCard>
<CCard>
<CCardHeader>Bar Chart</CCardHeader>
<CCardBody><CChartBarExample/></CCardBody>
</CCard>
<CCard>
<CCardHeader>Doughnut Chart</CCardHeader>
<CCardBody><CChartDoughnutExample/></CCardBody>
</CCard>
<CCard>
<CCardHeader>Radar Chart</CCardHeader>
<CCardBody><CChartRadarExample/></CCardBody>
</CCard>
<CCard>
<CCardHeader>Pie Chart</CCardHeader>
<CCardBody><CChartPieExample/></CCardBody>
</CCard>
<CCard>
<CCardHeader>Polar Area Chart</CCardHeader>
<CCardBody><CChartPolarAreaExample/></CCardBody>
</CCard>
<CCard>
<CCardHeader>Simple line chart</CCardHeader>
<CCardBody>
<CChartLineSimple border-color="success" labels="months"/>
</CCardBody>
</CCard>
<CCard>
<CCardHeader>Simple pointed chart</CCardHeader>
<CCardBody><CChartLineSimple pointed border-color="warning"/></CCardBody>
</CCard>
<CCard>
<CCardHeader>Simple bar chart</CCardHeader>
<CCardBody><CChartBarSimple background-color="danger"/></CCardBody>
</CCard>
</CCardGroup>
</div>
</template>
<script>
import * as Charts from './index.js'
export default {
name: 'Charts',
components: {
...Charts
}
}
</script>

View File

@@ -0,0 +1,103 @@
<template>
<CChartLine
:datasets="defaultDatasets"
:options="defaultOptions"
:labels="['Mo', 'Tu', 'We', 'Th', 'Fr', 'Sa', 'Su', 'Mo', 'Tu', 'We', 'Th', 'Fr', 'Sa', 'Su', 'Mo', 'Tu', 'We', 'Th', 'Fr', 'Sa', 'Su', 'Mo', 'Tu', 'We', 'Th', 'Fr', 'Sa', 'Su']"
/>
</template>
<script>
import { CChartLine } from '@coreui/vue-chartjs'
import { getStyle, hexToRgba } from '@coreui/utils/src'
function random (min, max) {
return Math.floor(Math.random() * (max - min + 1) + min)
}
export default {
name: 'MainChartExample',
components: {
CChartLine
},
computed: {
defaultDatasets () {
const brandSuccess = getStyle('success2') || '#4dbd74'
const brandInfo = getStyle('info') || '#20a8d8'
const brandDanger = getStyle('danger') || '#f86c6b'
let elements = 27
const data1 = []
const data2 = []
const data3 = []
for (let i = 0; i <= elements; i++) {
data1.push(random(50, 200))
data2.push(random(80, 100))
data3.push(65)
}
return [
{
label: 'My First dataset',
backgroundColor: hexToRgba(brandInfo, 10),
borderColor: brandInfo,
pointHoverBackgroundColor: brandInfo,
borderWidth: 2,
data: data1
},
{
label: 'My Second dataset',
backgroundColor: 'transparent',
borderColor: brandSuccess,
pointHoverBackgroundColor: brandSuccess,
borderWidth: 2,
data: data2
},
{
label: 'My Third dataset',
backgroundColor: 'transparent',
borderColor: brandDanger,
pointHoverBackgroundColor: brandDanger,
borderWidth: 1,
borderDash: [8, 5],
data: data3
}
]
},
defaultOptions () {
return {
maintainAspectRatio: false,
legend: {
display: false
},
scales: {
xAxes: [{
gridLines: {
drawOnChartArea: false
}
}],
yAxes: [{
ticks: {
beginAtZero: true,
maxTicksLimit: 5,
stepSize: Math.ceil(250 / 5),
max: 250
},
gridLines: {
display: true
}
}]
},
elements: {
point: {
radius: 0,
hitRadius: 10,
hoverRadius: 4,
hoverBorderWidth: 3
}
}
}
}
}
}
</script>

19
src/views/charts/index.js Normal file
View File

@@ -0,0 +1,19 @@
import CChartLineSimple from './CChartLineSimple'
import CChartBarSimple from './CChartBarSimple'
import CChartLineExample from './CChartLineExample'
import CChartBarExample from './CChartBarExample'
import CChartDoughnutExample from './CChartDoughnutExample'
import CChartRadarExample from './CChartRadarExample'
import CChartPieExample from './CChartPieExample'
import CChartPolarAreaExample from './CChartPolarAreaExample'
export {
CChartLineSimple,
CChartBarSimple,
CChartLineExample,
CChartBarExample,
CChartDoughnutExample,
CChartRadarExample,
CChartPieExample,
CChartPolarAreaExample
}

View File

@@ -0,0 +1,97 @@
<template>
<CCard>
<CCardHeader>
<h2>City List</h2>
</CCardHeader>
<CCardBody>
<CDataTable :items="cityList" :fields="cityFields">
<template #name="{ item }">
<td>
<router-link
:to="{ name: 'view-city', params: { name: item.name } }"
>{{ item.name }}</router-link
>
</td>
</template>
<template #planet="{ item }">
<td>
{{ titleCase(item.planet) }}
</td>
</template>
</CDataTable>
</CCardBody>
</CCard>
</template>
<script>
import { mapGetters } from 'vuex';
const CITY_FIELDS = [
{
label: 'City Name',
key: 'name',
},
{
label: 'Planet',
key: 'planet',
},
{
label: 'Rank',
key: 'rank',
},
];
export default {
name: 'CityList',
computed: {
...mapGetters('city', ['cities']),
cityList() {
if (!this.cities || this.cities.length === 0) return [];
let cities = [];
this.cities.forEach((city) => {
if (city.propertyLists && city.propertyLists.length > 0) {
let detail = city.propertyLists
.find((p) => p.listId === 12)
.value.split(':');
let c = {
name: detail[2],
planet: detail[4],
rank: this.parseRank(detail[7]),
};
cities.push(c);
}
});
return cities;
},
cityFields() {
return CITY_FIELDS;
},
},
methods: {
parseRank(val) {
switch (val) {
case 150:
return 1;
case 200:
return 2;
case 300:
return 3;
case 400:
return 4;
case 450:
return 5;
default:
return 0;
}
},
titleCase(val) {
if (!val) return;
return val.charAt(0).toUpperCase() + val.substr(1);
},
},
beforeRouteEnter(to, from, next) {
next((vm) => {
vm.$store.dispatch('city/fetchAll');
});
},
};
</script>

365
src/views/city/ViewCity.vue Normal file
View File

@@ -0,0 +1,365 @@
<template>
<div>
<div v-if="dataHasLoaded">
<CCard>
<CCardHeader>
<h2>
<strong>{{ city.name }}</strong> - City Details
</h2>
</CCardHeader>
<CCardBody>
<CRow>
<CCol>
<h4>Administration:</h4>
<CRow>
<CCol>
<label class="mr-4 mb-4 mt-2">Mayor:</label>
<router-link
v-if="city.mayor"
class="ml-5"
:to="{
name: 'view-player',
params: { objectId: city.mayor.objectId },
}"
>
{{ city.mayor.characterFullName }}
</router-link>
</CCol>
</CRow>
<CRow>
<CCol>
<CInput
label="Established:"
:value="convertMillisToDate(city.created)"
plaintext
horizontal
/>
</CCol>
</CRow>
<CRow>
<CCol>
<CInput
label="Current Rank:"
:value="city.rank"
plaintext
horizontal
/>
</CCol>
</CRow>
</CCol>
<CCol>
<h4>Location:</h4>
<CRow>
<CCol>
<CInput
label="Planet:"
:value="titleCase(city.planet)"
plaintext
horizontal
/>
</CCol>
</CRow>
<CRow>
<CCol>
<CInput label="X:" :value="city.x" plaintext horizontal />
</CCol>
</CRow>
<CRow>
<CCol>
<CInput label="Z:" :value="city.z" plaintext horizontal />
</CCol>
</CRow>
<CRow>
<CCol>
<CInput
label="City Radius:"
:value="city.radius + 'm'"
plaintext
horizontal
/>
</CCol>
</CRow>
</CCol>
<CCol>
<h4>Financial:</h4>
<CRow>
<CCol>
<CInput
label="Income Tax:"
:value="city.taxes.income"
plaintext
horizontal
/>
</CCol>
</CRow>
<CRow>
<CCol>
<CInput
label="Property Tax:"
:value="city.taxes.property"
plaintext
horizontal
/>
</CCol>
</CRow>
<CRow>
<CCol>
<CInput
label="Sales Tax:"
:value="city.taxes.sales"
plaintext
horizontal
/>
</CCol>
</CRow>
</CCol>
</CRow>
<CRow>
<CCol>
<CTabs>
<CTab title="Citizens">
<CDataTable :items="citizens" :fields="citizenFields">
<template #name="{ item }">
<td>
<router-link
:to="{
name: 'view-player',
params: { objectId: item.objectId },
}"
>{{ item.name }}</router-link
>
</td>
</template>
</CDataTable>
</CTab>
<CTab title="Structures">
<CDataTable :items="structures" :fields="structureFields">
<template #valid="{ item }">
<td>
<CBadge
:color="item.valid == 1 ? 'success' : 'danger'"
>{{ item.valid == 1 ? 'Valid' : 'Invalid' }}</CBadge
>
</td>
</template>
</CDataTable>
</CTab>
</CTabs>
</CCol>
</CRow>
</CCardBody>
</CCard>
</div>
<div v-else>
<h1>City "{{ name }}" could not be found!</h1>
</div>
</div>
</template>
<script>
import SwgApi from '@/api';
const CITIZEN_FIELDS = [
{
label: 'Name',
key: 'name',
},
{
label: 'Template',
key: 'template',
},
{
label: 'Level',
key: 'level',
},
];
const STRUCTURE_FIELDS = [
{
label: 'Building ID',
key: 'objectId',
},
{
label: 'Type',
key: 'type',
},
{
label: 'Valid',
key: 'valid',
},
];
export default {
name: 'ViewCity',
props: {
name: {
type: String,
required: true,
},
},
computed: {
citizenFields() {
return CITIZEN_FIELDS;
},
citizens() {
if (!this.city || !this.city.citizens) return;
let citizenList = [];
let c = null;
this.city.citizens.forEach((ci) => {
let citizen = ci.value.split(':');
if (citizen[0] === 'v2') {
c = {
objectId: citizen[2],
name: citizen[3],
template: citizen[4],
level: citizen[5],
title: citizen[6],
allegiance: citizen[7],
permissions: citizen[8],
rank: citizen[9],
};
} else {
c = {
objectId: citizen[1],
name: citizen[2],
template: 'Not Listed',
level: 'Not Listed',
allegiance: citizen[3],
permissions: citizen[4],
};
}
citizenList.push(c);
});
return citizenList;
},
structures() {
if (!this.city || !this.city.structures) return;
let structureList = [];
let s = null;
this.city.structures.forEach((st) => {
let struct = st.value.split(':');
s = {
objectId: struct[1],
type: struct[2],
valid: struct[3],
};
structureList.push(s);
});
return structureList;
},
structureFields() {
return STRUCTURE_FIELDS;
},
},
methods: {
fetchData(name) {
SwgApi.city
.getCityDetail(name)
.then((c) => {
this.spread(c);
})
.catch((e) => {
console.error('Error: ', { ...e });
});
},
spread(city) {
// the object from string definition is in CityStringParser.cpp
this.city.citizens = city.propertyLists.filter((pl) => pl.listId === 13);
this.city.structures = city.propertyLists.filter(
(pl) => pl.listId === 14
);
let pl = city.propertyLists
.find((pl) => pl.listId === 12)
.value.split(':');
this.city.id = pl[1];
this.city.name = pl[2];
this.city.planet = pl[4];
this.city.x = pl[5];
this.city.z = pl[6];
this.city.radius = pl[7];
this.city.created = pl[8];
this.getCityMayor(pl[9]);
this.city.taxes.income = pl[10];
this.city.taxes.property = pl[11];
this.city.taxes.sales = pl[12];
this.city.travelCost = pl[16];
this.city.rank = 'Rank ' + this.parseRank(pl[7]);
//this.getCityFaction(pl[3]);
this.dataHasLoaded = true;
},
parseRank(val) {
switch (val) {
case 150:
return 1;
case 200:
return 2;
case 300:
return 3;
case 400:
return 4;
case 450:
return 5;
default:
return 0;
}
},
getCityMayor(objectId) {
SwgApi.player.getPlayerDetail(objectId).then((p) => {
this.city.mayor = p;
});
},
getCityFaction(factionId) {
return 'Imperial';
// SwgApi.faction.getFaction(factionId).then((f) => {
// this.city.faction = f;
// });
},
titleCase(val) {
if (!val) return;
return val.charAt(0).toUpperCase() + val.substr(1);
},
convertMillisToDate(millis) {
let d = new Date(millis * 1000);
return d.toLocaleString();
},
},
data() {
return {
// the object from string definition is in CityStringParser.cpp
city: {
id: null,
name: null,
cityHallObjectId: null,
planet: null,
x: null,
z: null,
radius: null,
created: null,
mayor: null,
taxes: {
income: null,
property: null,
sales: null,
},
travelLocation: null,
travelCost: null,
travelInterplanetary: null,
cloneLocation: null,
cloneRespawn: null,
faction: null,
rank: null,
citizens: [],
},
dataHasLoaded: false,
};
},
watch: {
$route(to, from) {
this.fetchData(to.params.name);
},
},
beforeRouteEnter(to, from, next) {
next((vm) => {
vm.fetchData(to.params.name);
});
},
};
</script>

View File

@@ -0,0 +1,51 @@
<template>
<div>
<h4>
You're viewing details for player
<strong>{{ player.characterFullName }}</strong>
</h4>
</div>
</template>
<script>
import SwgApi from '@/api';
export default {
name: 'ViewPlayer',
props: {
objectId: {
type: String,
required: true,
},
},
methods: {
fetchData(objectId) {
SwgApi.player
.getPlayerDetail(objectId)
.then((c) => {
this.spread(c);
})
.catch((e) => {
console.error('Error: ', { ...e });
});
},
spread(player) {
this.player = player;
},
},
data() {
return {
player: null,
};
},
watch: {
$route(to, from) {
this.fetchData(to.params.objectId);
},
},
beforeRouteEnter(to, from, next) {
next((vm) => {
vm.fetchData(to.params.objectId);
});
},
};
</script>

View File

@@ -0,0 +1,97 @@
<template>
<div v-if="this.planets && this.centralServer">
<CCard>
<CCardHeader>
<h2>Game Settings</h2>
</CCardHeader>
</CCard>
<CCard>
<CCardBody>
<CTabs>
<CTab>
<template slot="title">
<CIcon name="cil-settings" /> Admin
</template>
<AdminTab />
</CTab>
<CTab>
<template slot="title">
<CIcon name="cil-user" /> Players
</template>
<PlayersTab />
</CTab>
<CTab>
<template slot="title">
<CIcon name="cil-home" /> Structures
</template>
<StructuresTab />
</CTab>
<CTab>
<template slot="title">
<CIcon name="cil-building" /> Cities
</template>
<CitiesTab />
</CTab>
<CTab>
<template slot="title"> <CIcon name="cil-user" /> Events </template>
<EventsTab />
</CTab>
<CTab>
<template slot="title">
<CIcon name="cil-globe-alt" /> Planets
</template>
<PlanetsTab />
</CTab>
<CTab>
<template slot="title">
<CIcon name="cil-money" /> Commodities
</template>
<CommoditiesTab />
</CTab>
<CTab>
<template slot="title">
<CIcon name="cil-healing" /> Combat
</template>
<CombatTab />
</CTab>
<CTab>
<template slot="title">
<CIcon name="cil-bar-chart" /> Metrics
</template>
<MetricsTab />
</CTab>
</CTabs>
</CCardBody>
</CCard>
</div>
</template>
<script>
import SettingsMixin from '@/views/settings/mixins/settings-mixin';
import {
AdminTab,
PlanetsTab,
PlayersTab,
CommoditiesTab,
CombatTab,
MetricsTab,
CitiesTab,
EventsTab,
StructuresTab,
} from '@/views/settings/tabs';
export default {
name: 'GameSettings',
mixins: [SettingsMixin],
components: {
AdminTab,
PlanetsTab,
PlayersTab,
CommoditiesTab,
CombatTab,
MetricsTab,
CitiesTab,
EventsTab,
StructuresTab,
},
};
</script>

View File

@@ -0,0 +1,73 @@
<template>
<div>
<CCard>
<CCardHeader>
<h2>Logging Settings</h2>
</CCardHeader>
</CCard>
<CCard>
<CCardBody>
<CRow>
<CCol col="4">
<SettingsCard title="General Settings">
<Toggle
class="server-config"
label="Chat Server Logging:"
:checked="chatServer.loggingEnabled"
property="chatServer.loggingEnabled"
@update:checked="updateProperty"
/>
<Toggle
class="server-config"
label="Game AI Logging:"
:checked="gameServer.aiLoggingEnabled"
property="gameServer.aiLoggingEnabled"
@update:checked="updateProperty"
/>
<Toggle
class="server-config"
label="Report AI Warnings:"
:checked="gameServer.reportAiWarnings"
property="gameServer.reportAiWarnings"
@update:checked="updateProperty"
/>
<Toggle
class="server-config"
label="Java Console Debug:"
:checked="gameServer.javaConsoleDebugMessages"
property="gameServer.javaConsoleDebugMessages"
@update:checked="updateProperty"
/>
</SettingsCard>
</CCol>
<CCol col="4">
<SettingsCard title="Logs">
<CInput
:value="
getPropertyValue('sharedLog.logTarget').replace('net:', '')
"
label="Logging Server Address:"
@update="
(e) => {
updateProperty({
property: 'sharedLog.logTarget',
value: 'net:' + e,
});
}
"
/>
</SettingsCard>
</CCol>
</CRow>
</CCardBody>
</CCard>
</div>
</template>
<script>
import SettingsMixin from '@/views/settings/mixins/settings-mixin';
export default {
name: 'LoggingSettings',
mixins: [SettingsMixin],
};
</script>

View File

@@ -0,0 +1,162 @@
<template>
<div>
<CCard>
<CCardHeader>
<h2>Server Settings</h2>
</CCardHeader>
</CCard>
<CCard>
<CCardBody>
<CRow>
<CCol col="6">
<SettingsCard title="General Settings">
<Toggle
class="server-config"
label="External Access:"
:checked="loginServer.easyExternalAccess"
property="loginServer.easyExternalAccess"
@update:checked="updateProperty"
/>
<Toggle
class="server-config"
label="Development Mode:"
:checked="centralServer.developmentMode"
property="centralServer.developmentMode"
@update:checked="updateProperty"
/>
<CSelect
label="Server Load Level:"
:value="gameServer.serverLoadLevel"
property="gameServer.serverLoadLevel"
:options="['light', 'medium', 'heavy']"
@update="updateProperty"
:horizontal="{ label: 'col-sm-6', input: 'col-sm-6' }"
/>
<Toggle
class="server-config"
label="Persist Created Objects:"
:checked="gameServer.adminPersistAllCreates"
property="gameServer.adminPersistAllCreates"
@update:checked="updateProperty"
/>
<Toggle
class="server-config"
label="Buildout Area Editing:"
:checked="gameServer.buildoutAreaEditingEnabled"
property="gameServer.buildoutAreaEditingEnabled"
@update:checked="updateProperty"
/>
<TimerInput
label="Weather Update (seconds):"
unit="seconds"
:value="getPropertyValue('gameServer.weatherUpdateSeconds')"
@update="
(e) => {
updateProperty({
property: 'gameServer.weatherUpdateSeconds',
value: e,
});
}
"
:horizontal="{ label: 'col-sm-6', input: 'col-sm-6' }"
/>
<CInput
label="Max. Lots Per Account:"
type="number"
v-integer-only
:value="getPropertyValue('gameServer.maxLotsPerAccount')"
@update="
(e) => {
updateProperty({
property: 'gameServer.maxLotsPerAccount',
value: e,
});
}
"
:horizontal="{ label: 'col-sm-6', input: 'col-sm-6' }"
/>
<CRow>
<CCol>
<CInput
label="Admin Account Table:"
:value="
getPropertyValue('gameServer.adminAccountDataTable')
"
@update="
(e) => {
updateProperty({
property: 'gameServer.adminAccountDataTable',
value: e,
});
}
"
:horizontal="{ label: 'col-sm-6', input: 'col-sm-6' }"
/>
</CCol>
</CRow>
<CRow>
<CCol>
<h5>God Mode</h5>
</CCol>
</CRow>
<CRow>
<CCol>
<Toggle
class="mt-1 admin-config"
label="God Mode:"
:checked="gameServer.adminGodToAll"
property="gameServer.adminGodToAll"
@update:checked="updateProperty"
/>
</CCol>
<CCol>
<CInput
label="Level:"
:value="
getPropertyValue('gameServer.adminGodToAllGodLevel')
"
@update="
(e) => {
updateProperty({
property: 'gameServer.adminGodToAllGodLevel',
value: e,
});
}
"
:disabled="!gameServer.adminGodToAll"
:horizontal="{ label: 'col-sm-6', input: 'col-sm-6' }"
/>
</CCol>
</CRow>
</SettingsCard>
</CCol>
</CRow>
</CCardBody>
</CCard>
</div>
</template>
<style lang="scss">
.server-config {
label:first-of-type {
width: 175px;
}
}
.resource-config {
label:first-of-type {
width: 175px;
}
}
.admin-config {
label:first-of-type {
width: 75px;
}
}
</style>
<script>
import SettingsMixin from '@/views/settings/mixins/settings-mixin';
export default {
name: 'ServerSettings',
mixins: [SettingsMixin],
};
</script>

View File

@@ -0,0 +1,130 @@
import { mapGetters } from 'vuex';
import Toggle from '@/components/Toggle.vue';
import TimerInput from '@/components/TimerInput.vue';
import SettingsCard from '@/components/SettingsCard';
const DAY_OPTIONS = [
{
label: 'Sunday',
value: 0,
},
{
label: 'Monday',
value: 1,
},
{
label: 'Tuesday',
value: 2,
},
{
label: 'Wednesday',
value: 3,
},
{
label: 'Thursday',
value: 4,
},
{
label: 'Friday',
value: 5,
},
{
label: 'Saturday',
value: 6,
},
];
export default {
components: { Toggle, TimerInput, SettingsCard },
computed: {
...mapGetters('settings', ['settings']),
planets() {
if (!this.settings.centralServer) return;
return this.settings.centralServer.startPlanet;
},
bestineEvents() {
if (!this.settings || !this.settings.bestineEvents) return;
return this.settings.bestineEvents;
},
dungeon() {
if (!this.settings || !this.settings.dungeon) return;
return this.settings.dungeon;
},
eventTeam() {
if (!this.settings || !this.settings.eventTeam) return;
return this.settings.eventTeam;
},
centralServer() {
if (!this.settings || !this.settings.centralServer) return;
return this.settings.centralServer;
},
characterBuilder() {
if (!this.settings || !this.settings.characterBuilder) return;
return this.settings.characterBuilder;
},
chatServer() {
if (!this.settings || !this.settings.chatServer) return;
return this.settings.chatServer;
},
commodityServer() {
if (!this.settings || !this.settings.commodityServer) return;
return this.settings.commodityServer;
},
custom() {
if (!this.settings || !this.settings.custom) return;
return this.settings.custom;
},
gameServer() {
if (!this.settings || !this.settings.gameServer) return;
return this.settings.gameServer;
},
loginServer() {
if (!this.settings || !this.settings.loginServer) return;
return this.settings.loginServer;
},
sharedLog() {
if (!this.settings || !this.settings.sharedLog) return;
return this.settings.sharedLog;
},
npeStatus: {
get() {
this.tutorialStatus = this.getPropertyValue(
'centralServer.newbieTutorialEnabled'
);
return this.tutorialStatus;
},
set(v) {
this.tutorialStatus = v;
this.updateProperty({
property: 'centralServer.newbieTutorialEnabled',
value: v,
});
},
},
dayOptions() {
return DAY_OPTIONS;
},
},
methods: {
getPlanet(name) {
return this.planets.find((p) => p.name === name);
},
getPropertyValue(name) {
let tree = name.split('.');
return this.settings[tree[0]][tree[1]];
},
updateProperty(event) {
this.$store.dispatch('settings/updateProperty', event);
},
},
data() {
return {
base: true,
kashyyyk: true,
space: true,
tutorial: true,
instances: true,
tutorialStatus: false,
};
},
};

View File

@@ -0,0 +1,110 @@
<template>
<CModal
:show="show"
size="lg"
@update:show="
(e) => {
this.$emit('update:show', e);
}
"
>
<template #header>
<h4><strong>Information Kiosk</strong></h4>
</template>
<CCard>
<CCardBody>
<CRow>
<CCol>
<strong>Vendor Status:</strong> A player vendor goes through several
states before it is considered abandoned and ultimately removed from
the game.
<p>
The first state, <strong>'Active'</strong>, indicates the vendor
has items on it (either for sale or in the stock room) and has not
entered an 'Unaccessed' state.
</p>
<p>
The second state, <strong>'Unaccessed'</strong>, is triggered when
a vendor has either been empty or active after an indicated number
of minutes.
</p>
<p>
The final state, <strong>'Endangered'</strong>, is whan a vendor
has been Empty or Unaccessed for an indicated number of minutes.
</p></CCol
>
</CRow>
<CRow>
<CCol col="4">
<strong>Empty Time (in minutes):</strong>
</CCol>
<CCol>
This setting indicates the number of minutes that need to pass from
when a vendor has been found to be empty until it enters an
Endangered (about to be removed) status.
</CCol>
</CRow>
<CRow>
<CCol col="4">
<strong>Active Time (in minutes):</strong>
</CCol>
<CCol>
This setting indicates the number of minutes that can pass between
vendor accesses before it is considered 'Unaccessed'.
</CCol>
</CRow>
<CRow class="mt-2">
<CCol col="4">
<strong>Unaccessed Time (in minutes):</strong>
</CCol>
<CCol>
This setting indicates the number of minutes a vendor can be in an
'Unaccessed' status before it becomes 'Endangered' to be removed
from the game.
</CCol>
</CRow>
<CRow class="mt-2">
<CCol col="4">
<strong>Endangered Time (in minutes):</strong>
</CCol>
<CCol>
This setting indicates the number of minutes a vendor can be
'Endangered' before it is ultimately completely removed from the
game.
</CCol>
</CRow>
<CRow class="mt-2">
<CCol col="4">
<strong>Auction Time (in minutes):</strong>
</CCol>
<CCol>
This setting indicates how long an item will be put up for Auction
Bid before it is no longer available to be bid on.
</CCol>
</CRow>
<CRow class="mt-2">
<CCol col="4">
<strong>Item Time (in minutes):</strong>
</CCol>
<CCol>
This setting indicates how long an item is available for players to
purchase it.
</CCol>
</CRow>
</CCardBody>
</CCard>
<template #footer>
<CButton color="primary" @click="$emit('update:show', false)"
>Ok, Got It!</CButton
>
</template>
</CModal>
</template>
<script>
export default {
name: 'VendorHelpModal',
props: {
show: Boolean,
},
};
</script>

View File

@@ -0,0 +1,201 @@
<template>
<div>
<CRow class="mt-3">
<CCol>
<SettingsCard title="Resources">
<Toggle
class="resource-config"
label="Resources Enabled:"
:checked="!gameServer.disableResources"
property="gameServer.disableResources"
@update:checked="updateProperty"
inverse
/>
<Toggle
class="resource-config"
label="Spawn All Resources:"
:checked="gameServer.spawnAllResources"
property="gameServer.spawnAllResources"
@update:checked="updateProperty"
inverse
/>
<TimerInput
label="Resource Time Scale (seconds):"
unit="seconds"
:value="getPropertyValue('gameServer.resourceTimeScale')"
@update="
(e) => {
updateProperty({
property: 'gameServer.resourceTimeScale',
value: e,
});
}
"
:horizontal="{ label: 'col-sm-6', input: 'col-sm-6' }"
/>
<TimerInput
label="Resource Gathering Tick (seconds):"
unit="seconds"
:value="getPropertyValue('gameServer.secondsPerResourceTick')"
@update="
(e) => {
updateProperty({
property: 'gameServer.secondsPerResourceTick',
value: e,
});
}
"
:horizontal="{ label: 'col-sm-6', input: 'col-sm-6' }"
/>
</SettingsCard>
</CCol>
<CCol>
<SettingsCard title="Galactic Civil War">
<h5>GCW Recalculation (GMT)</h5>
<CSelect
:value="getPropertyValue('gameServer.gcwRecalcTimeDayOfWeek')"
:options="dayOptions"
label="Day of Week:"
@update="
(e) => {
updateProperty({
property: 'gameServer.gcwRecalcTimeDayOfWeek',
value: e,
});
}
"
:horizontal="{ label: 'col-sm-6', input: 'col-sm-6' }"
/>
<CRow>
<CCol>
<CInput
:value="getPropertyValue('gameServer.gcwRecalcTimeHour')"
label="Hour:"
@update="
(e) => {
updateProperty({
property: 'gameServer.gcwRecalcTimeHour',
value: e,
});
}
"
/>
</CCol>
<CCol>
<CInput
:value="getPropertyValue('gameServer.gcwRecalcTimeMinute')"
label="Minute:"
@update="
(e) => {
updateProperty({
property: 'gameServer.gcwRecalcTimeMinute',
value: e,
});
}
"
/>
</CCol>
<CCol>
<CInput
:value="getPropertyValue('gameServer.gcwRecalcTimeSecond')"
label="Second:"
@update="
(e) => {
updateProperty({
property: 'gameServer.gcwRecalcTimeSecond',
value: e,
});
}
"
/>
</CCol>
</CRow>
<h5>GCW Decay</h5>
<CSelect
:value="getPropertyValue('gameServer.gcwScoreDecayTimeDayOfWeek')"
:options="dayOptions"
label="Day of Week:"
@update="
(e) => {
updateProperty({
property: 'gameServer.gcwScoreDecayTimeDayOfWeek',
value: e,
});
}
"
:horizontal="{ label: 'col-sm-6', input: 'col-sm-6' }"
/>
<CRow>
<CCol>
<CInput
:value="getPropertyValue('gameServer.gcwScoreDecayTimeHour')"
label="Hour:"
@update="
(e) => {
updateProperty({
property: 'gameServer.gcwScoreDecayTimeHour',
value: e,
});
}
"
/>
</CCol>
<CCol>
<CInput
:value="getPropertyValue('gameServer.gcwScoreDecayTimeMinute')"
label="Minute:"
@update="
(e) => {
updateProperty({
property: 'gameServer.gcwScoreDecayTimeMinute',
value: e,
});
}
"
/>
</CCol>
<CCol>
<CInput
:value="getPropertyValue('gameServer.gcwScoreDecayTimeSecond')"
label="Second:"
@update="
(e) => {
updateProperty({
property: 'gameServer.gcwScoreDecayTimeSecond',
value: e,
});
}
"
/>
</CCol>
</CRow>
</SettingsCard>
</CCol>
</CRow>
</div>
</template>
<style lang="scss">
.server-config {
label:first-of-type {
width: 175px;
}
}
.resource-config {
label:first-of-type {
width: 175px;
}
}
.admin-config {
label:first-of-type {
width: 75px;
}
}
</style>
<script>
import SettingsMixin from '@/views/settings/mixins/settings-mixin';
export default {
name: 'AdminTab',
mixins: [SettingsMixin],
};
</script>

View File

@@ -0,0 +1,147 @@
<template>
<div>
<CRow class="mt-3">
<CCol class="col-xl-4 col-sm-6">
<SettingsCard
title="General Settings"
description="General settings for Player Cities."
>
<TimerInput
label="House Packup Eligibility Time (seconds):"
unit="seconds"
:value="
getPropertyValue(
'gameServer.cityCitizenshipInactivePackupInactiveTimeSeconds'
)
"
@update="
(e) => {
updateProperty({
property:
'gameServer.cityCitizenshipInactivePackupInactiveTimeSeconds',
value: e,
});
}
"
:horizontal="{ label: 'col-sm-6', input: 'col-sm-6' }"
/>
</SettingsCard>
</CCol>
<CCol class="col-xl-4 col-sm-6">
<SettingsCard title="Factional Presence">
<CInput
label="City Age Bonus:"
append="%"
:value="
getPropertyValue(
'gameServer.gcwFactionalPresenceAlignedCityAgeBonusPct'
)
"
@update="
(e) => {
updateProperty({
property:
'gameServer.gcwFactionalPresenceAlignedCityAgeBonusPct',
value: e,
});
}
"
:horizontal="{ label: 'col-sm-6', input: 'col-sm-6' }"
/>
<CInput
label="City Bonus:"
append="%"
:value="
getPropertyValue(
'gameServer.gcwFactionalPresenceAlignedCityBonusPct'
)
"
@update="
(e) => {
updateProperty({
property:
'gameServer.gcwFactionalPresenceAlignedCityBonusPct',
value: e,
});
}
"
:horizontal="{ label: 'col-sm-6', input: 'col-sm-6' }"
/>
<CInput
label="City Rank Bonus:"
append="%"
:value="
getPropertyValue(
'gameServer.gcwFactionalPresenceAlignedCityRankBonusPct'
)
"
@update="
(e) => {
updateProperty({
property:
'gameServer.gcwFactionalPresenceAlignedCityRankBonusPct',
value: e,
});
}
"
:horizontal="{ label: 'col-sm-6', input: 'col-sm-6' }"
/>
<CInput
label="GCW Rank Bonus:"
append="%"
:value="
getPropertyValue('gameServer.gcwFactionalPresenceGcwRankBonusPct')
"
@update="
(e) => {
updateProperty({
property: 'gameServer.gcwFactionalPresenceGcwRankBonusPct',
value: e,
});
}
"
:horizontal="{ label: 'col-sm-6', input: 'col-sm-6' }"
/>
<CInput
label="City Level Bonus:"
append="%"
:value="getPropertyValue('gameServer.gcwFactionalPresenceLevelPct')"
@update="
(e) => {
updateProperty({
property: 'gameServer.gcwFactionalPresenceLevelPct',
value: e,
});
}
"
:horizontal="{ label: 'col-sm-6', input: 'col-sm-6' }"
/>
<CInput
label="Mounted Bonus:"
append="%"
:value="
getPropertyValue('gameServer.gcwFactionalPresenceMountedPct')
"
@update="
(e) => {
updateProperty({
property: 'gameServer.gcwFactionalPresenceMountedPct',
value: e,
});
}
"
:horizontal="{ label: 'col-sm-6', input: 'col-sm-6' }"
/>
</SettingsCard>
</CCol>
</CRow>
</div>
</template>
<script>
import SettingsMixin from '@/views/settings/mixins/settings-mixin';
export default {
name: 'CitiesTab',
mixins: [SettingsMixin],
};
</script>

View File

@@ -0,0 +1,229 @@
<template>
<CRow class="mt-3">
<CCol class="col-lg-4 col-sm-6">
<SettingsCard title="General">
<CInput
label="Max. Combat Range:"
append="Meters"
:value="getPropertyValue('gameServer.maxCombatRange')"
@update="
(e) => {
updateProperty({
property: 'gameServer.maxCombatRange',
value: e,
});
}
"
:horizontal="{ label: 'col-sm-6', input: 'col-sm-6' }"
/>
<Toggle
class="server-config"
label="PvP Enabled:"
:checked="!gameServer.pvpDisableCombat"
property="gameServer.pvpDisableCombat"
@update:checked="updateProperty"
inverse
/>
<CInput
label="Guild War Cooldown (millis):"
:value="
getPropertyValue('gameServer.pvpGuildWarCoolDownPeriodTimeMs')
"
@update="
(e) => {
updateProperty({
property: 'gameServer.pvpGuildWarCoolDownPeriodTimeMs',
value: e,
});
}
"
:horizontal="{ label: 'col-sm-6', input: 'col-sm-6' }"
/>
<h5 class="mt-3">Neutral Mercenary Support</h5>
<Toggle
class="server-config"
label="Enable Covert Imperial:"
:checked="gameServer.enableCovertImperialMercenary"
property="gameServer.enableCovertImperialMercenary"
@update:checked="updateProperty"
align-right
/>
<Toggle
class="server-config"
label="Enable Overt Imperial:"
:checked="gameServer.enableOvertImperialMercenary"
property="gameServer.enableOvertImperialMercenary"
@update:checked="updateProperty"
align-right
/>
<Toggle
class="server-config"
label="Enable Covert Rebel:"
:checked="gameServer.enableCovertRebelMercenary"
property="gameServer.enableCovertRebelMercenary"
@update:checked="updateProperty"
align-right
/>
<Toggle
class="server-config"
label="Enable Overt Rebel:"
:checked="gameServer.enableOvertRebelMercenary"
property="gameServer.enableOvertRebelMercenary"
@update:checked="updateProperty"
align-right
/>
</SettingsCard>
</CCol>
<CCol class="col-lg-4 col-sm-6">
<SettingsCard title="Regional Defender">
<CInput
label="Time Requirement:"
append="Days"
:value="
getPropertyValue(
'gameServer.gcwDaysRequiredForGcwRegionDefenderBonus'
)
"
@update="
(e) => {
updateProperty({
property: 'gameServer.gcwDaysRequiredForGcwRegionDefenderBonus',
value: e,
});
}
"
:horizontal="{ label: 'col-sm-6', input: 'col-sm-6' }"
/>
<CInput
label="Guild Size Requirement:"
:value="
getPropertyValue(
'gameServer.gcwGuildMinMembersForGcwRegionDefender'
)
"
@update="
(e) => {
updateProperty({
property: 'gameServer.gcwGuildMinMembersForGcwRegionDefender',
value: e,
});
}
"
:horizontal="{ label: 'col-sm-6', input: 'col-sm-6' }"
/>
<CInput
label="Total GCW Bonus:"
append="%"
:value="getPropertyValue('gameServer.gcwRegionDefenderTotalBonusPct')"
@update="
(e) => {
updateProperty({
property: 'gameServer.gcwRegionDefenderTotalBonusPct',
value: e,
});
}
"
:horizontal="{ label: 'col-sm-6', input: 'col-sm-6' }"
/>
</SettingsCard>
</CCol>
<CCol class="col-lg-4 col-sm-6">
<SettingsCard title="NPC Artificial Intelligence">
<CInput
label="Assist Radius:"
append="Meters"
:value="getPropertyValue('gameServer.aiAssistRadius')"
@update="
(e) => {
updateProperty({
property: 'gameServer.aiAssistRadius',
value: e,
});
}
"
:horizontal="{ label: 'col-sm-6', input: 'col-sm-6' }"
/>
<CInput
label="Base Aggro Radius:"
append="Meters"
:value="getPropertyValue('gameServer.aiBaseAggroRadius')"
@update="
(e) => {
updateProperty({
property: 'gameServer.aiBaseAggroRadius',
value: e,
});
}
"
:horizontal="{ label: 'col-sm-6', input: 'col-sm-6' }"
/>
<CInput
label="Leash Radius:"
append="Meters"
:value="getPropertyValue('gameServer.aiLeashRadius')"
@update="
(e) => {
updateProperty({
property: 'gameServer.aiLeashRadius',
value: e,
});
}
"
:horizontal="{ label: 'col-sm-6', input: 'col-sm-6' }"
/>
<CInput
label="Max. Aggro Radius:"
append="Meters"
:value="getPropertyValue('gameServer.aiMaxAggroRadius')"
@update="
(e) => {
updateProperty({
property: 'gameServer.aiMaxAggroRadius',
value: e,
});
}
"
:horizontal="{ label: 'col-sm-6', input: 'col-sm-6' }"
/>
<Toggle
class="server-config"
label="AI Sends Breadcrumbs:"
:checked="gameServer.sendBreadcrumbs"
property="gameServer.sendBreadcrumbs"
@update:checked="updateProperty"
/>
<TimerInput
label="Aggro Expiration Time:"
unit="seconds"
:value="
getPropertyValue('gameServer.defaultAutoExpireTargetDuration')
"
@update="
(e) => {
updateProperty({
property: 'gameServer.defaultAutoExpireTargetDuration',
value: e,
});
}
"
:horizontal="{ label: 'col-sm-6', input: 'col-sm-6' }"
/>
<Toggle
class="server-config"
label="Client Debug Enabled:"
:checked="gameServer.aiClientDebugEnabled"
property="gameServer.aiClientDebugEnabled"
@update:checked="updateProperty"
/>
</SettingsCard>
</CCol>
</CRow>
</template>
<script>
import SettingsMixin from '@/views/settings/mixins/settings-mixin';
export default {
name: 'CombatTab',
mixins: [SettingsMixin],
};
</script>

View File

@@ -0,0 +1,356 @@
<template>
<div>
<CRow class="mt-3">
<CCol class="col-lg-4 col-sm-6">
<CCard>
<CCardHeader>
<h3>General Settings</h3>
</CCardHeader>
<CCardBody>
<CRow class="mb-3">
<CCol
>Here you'll find settings related to the in-game commodities
system.
</CCol>
</CRow>
<CRow class="mb-2">
<CCol>
<Toggle
label="Commodity Market Enabled:"
:checked="gameServer.commoditiesMarketEnabled"
property="gameServer.commoditiesMarketEnabled"
@update:checked="updateProperty"
class="general-config"
/>
</CCol>
</CRow>
<CRow class="mb-2">
<CCol>
<Toggle
label="Show Debug Info in Console:"
:checked="gameServer.commoditiesShowAllDebugInfo"
property="gameServer.commoditiesShowAllDebugInfo"
@update:checked="updateProperty"
class="general-config"
/>
</CCol>
</CRow>
<CRow class="mb-2">
<CCol>
<CInput
label="Max. Credit Reimbursement:"
:value="getPropertyValue('gameServer.maxReimburseAmount')"
@update="
(e) => {
updateProperty({
property: 'gameServer.maxReimburseAmount',
value: e,
});
}
"
:horizontal="{ label: 'col-sm-6', input: 'col-sm-6' }"
/>
</CCol>
</CRow>
</CCardBody>
</CCard>
</CCol>
<CCol class="col-lg-4 col-sm-6">
<CCard>
<CCardHeader>
<h3>Bazaar Settings</h3>
</CCardHeader>
<CCardBody>
<CRow class="mb-3">
<CCol
>Here you'll find settings related to the in-game bazaar.
</CCol>
</CRow>
<CRow class="mb-2">
<CCol>
<Toggle
label="Player Bazaar Enabled:"
:checked="centralServer.auctionEnabled"
property="centralServer.auctionEnabled"
@update:checked="updateProperty"
/>
</CCol>
</CRow>
<CRow>
<CCol>
<CInput
label="Max. Auctions/Player:"
:value="
getPropertyValue('commodityServer.maxAuctionsPerPlayer')
"
@update="
(e) => {
updateProperty({
property: 'commodityServer.maxAuctionsPerPlayer',
value: e,
});
}
"
:horizontal="{ label: 'col-sm-5', input: 'col-sm-7' }"
/>
</CCol>
</CRow>
<CRow>
<CCol>
<TimerInput
label="Auction Bid Time (minutes):"
:value="
getPropertyValue(
'commodityServer.minutesBazaarAuctionTimer'
)
"
@update="
(e) => {
updateProperty({
property: 'commodityServer.minutesBazaarAuctionTimer',
value: e,
});
}
"
:horizontal="{ label: 'col-sm-5', input: 'col-sm-7' }"
/>
</CCol>
</CRow>
<CRow>
<CCol>
<TimerInput
label="Item Sale Time (minutes):"
:value="
getPropertyValue('commodityServer.minutesBazaarItemTimer')
"
@update="
(e) => {
updateProperty({
property: 'commodityServer.minutesBazaarItemTimer',
value: e,
});
}
"
:horizontal="{ label: 'col-sm-5', input: 'col-sm-7' }"
/>
</CCol>
</CRow>
<CRow>
<CCol>
<TimerInput
label="Unclaimed Item Time (seconds):"
unit="seconds"
:value="
getPropertyValue(
'gameServer.unclaimedAuctionItemDestroyTimeSec'
)
"
@update="
(e) => {
updateProperty({
property:
'gameServer.unclaimedAuctionItemDestroyTimeSec',
value: e,
});
}
"
:horizontal="{ label: 'col-sm-5', input: 'col-sm-7' }"
/>
</CCol>
</CRow>
</CCardBody>
</CCard>
</CCol>
<CCol class="col-lg-4 col-sm-6">
<CCard>
<CCardHeader>
<CRow>
<CCol col="9">
<h3>Vendor Settings</h3>
</CCol>
<CCol class="text-right mt-1">
<CLink @click="showHelp">
<CIcon
name="cil-comment-bubble-question"
style="height: 1.5rem; width: 1.5rem"
/>
</CLink>
</CCol>
</CRow>
</CCardHeader>
<CCardBody>
<CRow class="mb-3">
<CCol
>Here you'll find settings related to player controlled vendors
<div style="font-style: italic">
(Note: see the help icon in the upper right for more
information on these settings).
</div>
</CCol>
</CRow>
<CRow>
<CCol>
<TimerInput
label="Empty Time (minutes):"
:value="
getPropertyValue('commodityServer.minutesEmptyToEndangered')
"
@update="
(e) => {
updateProperty({
property: 'commodityServer.minutesEmptyToEndangered',
value: e,
});
}
"
:horizontal="{ label: 'col-sm-6', input: 'col-sm-6' }"
/>
</CCol>
</CRow>
<CRow>
<CCol>
<TimerInput
label="Active Time (minutes):"
:value="
getPropertyValue(
'commodityServer.minutesActiveToUnaccessed'
)
"
@update="
(e) => {
updateProperty({
property: 'commodityServer.minutesActiveToUnaccessed',
value: e,
});
}
"
:horizontal="{ label: 'col-sm-6', input: 'col-sm-6' }"
/>
</CCol>
</CRow>
<CRow>
<CCol>
<TimerInput
label="Unaccessed Time (minutes):"
:value="
getPropertyValue(
'commodityServer.minutesUnaccessedToEndangered'
)
"
@update="
(e) => {
updateProperty({
property:
'commodityServer.minutesUnaccessedToEndangered',
value: e,
});
}
"
:horizontal="{ label: 'col-sm-6', input: 'col-sm-6' }"
/>
</CCol>
</CRow>
<CRow>
<CCol>
<TimerInput
label="Endangered Time (minutes):"
:value="
getPropertyValue(
'commodityServer.minutesEndangeredToRemoved'
)
"
@update="
(e) => {
updateProperty({
property: 'commodityServer.minutesEndangeredToRemoved',
value: e,
});
}
"
:horizontal="{ label: 'col-sm-6', input: 'col-sm-6' }"
/>
</CCol>
</CRow>
<CRow>
<CCol>
<TimerInput
label="Auction Bid Time (minutes):"
:value="
getPropertyValue(
'commodityServer.minutesVendorAuctionTimer'
)
"
@update="
(e) => {
updateProperty({
property: 'commodityServer.minutesVendorAuctionTimer',
value: e,
});
}
"
:horizontal="{ label: 'col-sm-6', input: 'col-sm-6' }"
/>
</CCol>
</CRow>
<CRow>
<CCol>
<TimerInput
label="Item Sale Time (minutes):"
:value="
getPropertyValue('commodityServer.minutesVendorItemTimer')
"
@update="
(e) => {
updateProperty({
property: 'commodityServer.minutesVendorItemTimer',
value: e,
});
}
"
:horizontal="{ label: 'col-sm-6', input: 'col-sm-6' }"
/>
</CCol>
</CRow>
</CCardBody>
</CCard>
</CCol>
</CRow>
<VendorHelpModal
:show="showVendorHelpModal"
@update:show="
(e) => {
this.showVendorHelpModal = e;
}
"
/>
</div>
</template>
<style lang="scss">
.general-config {
label:first-of-type {
width: 185px;
}
}
</style>
<script>
import SettingsMixin from '@/views/settings/mixins/settings-mixin';
import VendorHelpModal from '@/views/settings/modals/VendorHelpModal';
export default {
name: 'BazaarTab',
mixins: [SettingsMixin],
components: {
VendorHelpModal,
},
methods: {
showHelp() {
this.showVendorHelpModal = true;
},
},
data() {
return {
showVendorHelpModal: false,
};
},
};
</script>

View File

@@ -0,0 +1,344 @@
<template>
<div>
<CRow class="mt-3">
<CCol class="col-xl-4 col-sm-6">
<SettingsCard title="World Events">
<Toggle
class="dungeon-config"
label="Galactic Civil War Raid:"
:checked="eventTeam.gcwRaid"
property="eventTeam.gcwRaid"
@update:checked="updateProperty"
align-right
/>
<Toggle
class="dungeon-config"
label="Anniversary:"
:checked="eventTeam.anniversary"
property="eventTeam.anniversary"
@update:checked="updateProperty"
align-right
/>
<h5 class="mt-3">Bestine</h5>
<TimerInput
label="Election Duration:"
unit="seconds"
:value="getPropertyValue('bestineEvents.politicianEventDuration')"
@update="
(e) => {
updateProperty({
property: 'bestineEvents.politicianEventDuration',
value: e,
});
}
"
:horizontal="{ label: 'col-sm-6', input: 'col-sm-6' }"
/>
<TimerInput
label="Museum Duration:"
unit="seconds"
:value="getPropertyValue('bestineEvents.museumEventDuration')"
@update="
(e) => {
updateProperty({
property: 'bestineEvents.museumEventDuration',
value: e,
});
}
"
:horizontal="{ label: 'col-sm-6', input: 'col-sm-6' }"
/>
<h5 class="mt-3">Restuss</h5>
<Toggle
class="dungeon-config"
label="Restuss Event:"
:checked="eventTeam.restussEvent"
property="eventTeam.restussEvent"
@update:checked="updateProperty"
align-right
/>
<CSelect
label="Restuss Phase:"
:value="eventTeam.restussPhase"
property="eventTeam.restussPhase"
:options="[
{ label: 'Stage 1 - Start', value: 0 },
{ label: 'Phase 2 - Invasion', value: 1 },
{ label: 'Phase 3 - Final', value: 2 },
]"
@update="updateProperty"
:horizontal="{ label: 'col-sm-6', input: 'col-sm-6' }"
/>
<Toggle
class="dungeon-config"
label="Actively Progress Event:"
:checked="eventTeam.restussProgressionOn"
property="eventTeam.restussProgressionOn"
@update:checked="updateProperty"
align-right
/>
</SettingsCard>
</CCol>
<CCol class="col-xl-4 col-sm-6">
<SettingsCard title="Chronicles">
<CInput
:value="getPropertyValue('gameServer.chroniclesXpModifier')"
v-float-only
type="number"
label="Experience Modifier:"
@update="
(e) => {
updateProperty({
property: 'gameServer.chroniclesXpModifier',
value: e,
});
}
"
:horizontal="{ label: 'col-sm-8', input: 'col-sm-4' }"
/>
<CInput
:value="
getPropertyValue(
'gameServer.chroniclesQuestorSilverTokenNumModifier'
)
"
v-float-only
type="number"
label="Questor Silver Award Modifier:"
@update="
(e) => {
updateProperty({
property:
'gameServer.chroniclesQuestorSilverTokenNumModifier',
value: e,
});
}
"
:horizontal="{ label: 'col-sm-8', input: 'col-sm-4' }"
/>
<CInput
:value="
getPropertyValue(
'gameServer.chroniclesChroniclerSilverTokenNumModifier'
)
"
v-float-only
type="number"
label="Chronicler Silver Award Modifier:"
@update="
(e) => {
updateProperty({
property:
'gameServer.chroniclesChroniclerSilverTokenNumModifier',
value: e,
});
}
"
:horizontal="{ label: 'col-sm-8', input: 'col-sm-4' }"
/>
<CInput
:value="
getPropertyValue(
'gameServer.chroniclesQuestorGoldTokenChanceOverride'
)
"
v-integer-only
type="number"
label="Questor Chance for Gold Token:"
@update="
(e) => {
updateProperty({
property:
'gameServer.chroniclesQuestorGoldTokenChanceOverride',
value: e,
});
}
"
:horizontal="{ label: 'col-sm-8', input: 'col-sm-4' }"
/>
<CInput
:value="
getPropertyValue(
'gameServer.chroniclesChroniclerGoldTokenChanceOverride'
)
"
v-integer-only
type="number"
label="Chronicler Chance for Gold Token:"
@update="
(e) => {
updateProperty({
property:
'gameServer.chroniclesChroniclerGoldTokenChanceOverride',
value: e,
});
}
"
:horizontal="{ label: 'col-sm-8', input: 'col-sm-4' }"
/>
</SettingsCard>
</CCol>
<CCol class="col-xl-4 col-sm-6">
<SettingsCard title="GCW Invasions">
<CSelect
label="Maximum Invasions Active:"
:value="gameServer.gcwInvasionCityMaximumRunning"
property="gameServer.gcwInvasionCityMaximumRunning"
:options="[{ label: '0 (Disabled)', value: 0 }, 1, 2, 3]"
@update="updateProperty"
:horizontal="{ label: 'col-sm-8', input: 'col-sm-4' }"
/>
<TimerInput
label="Invasion Cycle Time (hours):"
unit="hours"
:value="getPropertyValue('gameServer.gcwInvasionCycleTime')"
@update="
(e) => {
updateProperty({
property: 'gameServer.gcwInvasionCycleTime',
value: e,
});
}
"
:horizontal="{ label: 'col-sm-8', input: 'col-sm-4' }"
/>
<Toggle
class="dungeon-config"
label="Bestine Invasion:"
:checked="gameServer.gcwCityBestine"
property="gameServer.gcwCityBestine"
@update:checked="updateProperty"
align-right
/>
<Toggle
class="dungeon-config"
label="Dearic Invasion:"
:checked="gameServer.gcwCityDearic"
property="gameServer.gcwCityDearic"
@update:checked="updateProperty"
align-right
/>
<Toggle
class="dungeon-config"
label="Keren Invasion:"
:checked="gameServer.gcwCityKeren"
property="gameServer.gcwCityKeren"
@update:checked="updateProperty"
align-right
/>
</SettingsCard>
</CCol>
<CCol class="col-xl-4 col-sm-6">
<SettingsCard title="Dungeons">
<Toggle
class="dungeon-config"
label="Geonosian Bunker:"
:checked="dungeon.geonosian"
property="dungeon.geonosian"
@update:checked="updateProperty"
align-right
/>
<Toggle
class="dungeon-config"
label="Death Watch Bunker:"
:checked="dungeon.deathWatch"
property="dungeon.deathWatch"
@update:checked="updateProperty"
align-right
/>
<Toggle
class="dungeon-config"
label="Corellian Corvette - Neutral:"
:checked="dungeon.corellianCorvetteNeutral"
property="dungeon.corellianCorvetteNeutral"
@update:checked="updateProperty"
align-right
/>
<Toggle
class="dungeon-config"
label="Corellian Corvette - Imperial:"
:checked="dungeon.corellianCorvetteImperial"
property="dungeon.corellianCorvetteImperial"
@update:checked="updateProperty"
align-right
/>
<Toggle
class="dungeon-config"
label="Corellian Corvette - Rebel:"
:checked="dungeon.corellianCorvetteRebel"
property="dungeon.corellianCorvetteRebel"
@update:checked="updateProperty"
align-right
/>
</SettingsCard>
</CCol>
<CCol class="col-xl-4 col-sm-6">
<SettingsCard title="Holidays">
<Toggle
class="dungeon-config"
label="Dr. Fool (April Fools):"
:checked="gameServer.forceFoolsDay"
property="gameServer.forceFoolsDay"
@update:checked="updateProperty"
align-right
/>
<Toggle
class="dungeon-config"
label="Force Dr. Fool:"
:checked="gameServer.forceFoolsDay"
property="gameServer.forceFoolsDay"
@update:checked="updateProperty"
align-right
/>
<Toggle
class="dungeon-config"
label="Wookiee Life Day:"
:checked="gameServer.lifeday"
property="gameServer.lifeday"
@update:checked="updateProperty"
align-right
/>
<Toggle
class="dungeon-config"
label="Ewok Festival of Love:"
:checked="gameServer.loveday"
property="gameServer.loveday"
@update:checked="updateProperty"
align-right
/>
<Toggle
class="dungeon-config"
label="Galactic Moon Festival:"
:checked="gameServer.halloween"
property="gameServer.halloween"
@update:checked="updateProperty"
align-right
/>
<Toggle
class="dungeon-config"
label="Empire/Rememberance Day:"
:checked="gameServer.empireday_ceremony"
property="gameServer.empireday_ceremony"
@update:checked="updateProperty"
align-right
/>
</SettingsCard>
</CCol>
</CRow>
</div>
</template>
<style lang="scss">
.dungeon-config {
.switch-label {
width: 300px;
}
}
</style>
<script>
import SettingsMixin from '@/views/settings/mixins/settings-mixin';
export default {
name: 'EventsTab',
mixins: [SettingsMixin],
};
</script>

View File

@@ -0,0 +1,21 @@
import AdminTab from './admin-tab';
import PlanetsTab from './planets-tab';
import PlayersTab from './players-tab';
import CommoditiesTab from './commodities-tab';
import CombatTab from './combat-tab';
import MetricsTab from './metrics-tab';
import CitiesTab from './cities-tab';
import EventsTab from './events-tab';
import StructuresTab from './structures-tab';
export {
AdminTab,
PlanetsTab,
PlayersTab,
CommoditiesTab,
CombatTab,
MetricsTab,
CitiesTab,
EventsTab,
StructuresTab,
};

View File

@@ -0,0 +1,42 @@
<template>
<CRow class="mt-3">
<CCol class="col-lg-4 col-sm-6">
<SettingsCard title="General">
<CInput
label="Metrics URL:"
:value="getPropertyValue('centralServer.metricsDataURL')"
@update="
(e) => {
updateProperty({
property: 'centralServer.metricsDataURL',
value: e,
});
}
"
/>
<TimerInput
label="Update Interval (seconds):"
unit="seconds"
:value="getPropertyValue('centralServer.webUpdateIntervalSeconds')"
@update="
(e) => {
updateProperty({
property: 'centralServer.webUpdateIntervalSeconds',
value: e,
});
}
"
:horizontal="{ label: 'col-sm-6', input: 'col-sm-6' }"
/>
</SettingsCard>
</CCol>
</CRow>
</template>
<script>
import SettingsMixin from '@/views/settings/mixins/settings-mixin';
export default {
name: 'MetricsTab',
mixins: [SettingsMixin],
};
</script>

View File

@@ -0,0 +1,408 @@
<template>
<div>
<CRow class="mt-3">
<CCol>
<h3>Planets</h3>
Below, you will find a series of switches. These switches will turn a
planet or zone ON or OFF. Note: you will need to restart the server for
these changes to take effect.
</CCol>
</CRow>
<CRow class="mt-3">
<CCol xl="3" lg="4" sm="6" class="mb-3">
<CCard style="height: 100%">
<CCardHeader>
<CRow>
<CCol>
<h4>Base Planets</h4>
</CCol>
<CCol class="text-right">
<label
style="
vertical-align: top;
margin-right: 5px;
margin-top: 3px;
"
><strong>Enabled:</strong></label
>
<CSwitch
shape="pill"
color="primary"
:checked="base"
@update:checked="() => (base = !base)"
/>
</CCol>
</CRow>
</CCardHeader>
<CCardBody>
<PlanetSwitch
label="Corellia"
:planet="getPlanet('corellia')"
:active="base"
/>
<PlanetSwitch
label="Dantooine"
:planet="getPlanet('dantooine')"
:active="base"
/>
<PlanetSwitch
label="Dathomir"
:planet="getPlanet('dathomir')"
:active="base"
/>
<PlanetSwitch
label="Endor"
:planet="getPlanet('endor')"
:active="base"
/>
<PlanetSwitch
label="Lok"
:planet="getPlanet('lok')"
:active="base"
/>
<PlanetSwitch
label="Mustafar"
:planet="getPlanet('mustafar')"
:active="base"
/>
<PlanetSwitch
label="Naboo"
:planet="getPlanet('naboo')"
:active="base"
/>
<PlanetSwitch
label="Rori"
:planet="getPlanet('rori')"
:active="base"
/>
<PlanetSwitch
label="Talus"
:planet="getPlanet('talus')"
:active="base"
/>
<PlanetSwitch
label="Tatooine"
:planet="getPlanet('tatooine')"
:active="base"
/>
<PlanetSwitch
label="Yavin IV"
:planet="getPlanet('yavin4')"
:active="base"
/>
</CCardBody>
</CCard>
</CCol>
<CCol xl="3" lg="4" sm="6" class="mb-3">
<CCard style="height: 100%">
<CCardHeader>
<CRow>
<CCol>
<h4>Kashyyyk</h4>
</CCol>
<CCol class="text-right">
<label
style="
vertical-align: top;
margin-right: 5px;
margin-top: 3px;
"
><strong>Enabled:</strong></label
>
<CSwitch
shape="pill"
color="primary"
:checked="kashyyyk"
@update:checked="() => (kashyyyk = !kashyyyk)"
/>
</CCol>
</CRow>
</CCardHeader>
<CCardBody>
<PlanetSwitch
label="Kachirho"
:planet="getPlanet('kashyyyk_main')"
:active="kashyyyk"
/>
<PlanetSwitch
label="Etyyy Hunting Grounds"
:planet="getPlanet('kashyyyk_hunting')"
:active="kashyyyk"
/>
<PlanetSwitch
label="Kkowir Forest"
:planet="getPlanet('kashyyyk_dead_forest')"
:active="kashyyyk"
/>
<PlanetSwitch
label="North Dungeons"
sub-label="The Arena, Trando Slaver Camp"
:planet="getPlanet('kashyyyk_north_dungeons')"
:active="kashyyyk"
/>
<PlanetSwitch
label="POB Dungeons"
sub-label="Avatar Platform, Myyydril Caverns"
:planet="getPlanet('kashyyyk_pob_dungeons')"
:active="kashyyyk"
/>
<PlanetSwitch
label="Rryatt Trail"
:planet="getPlanet('kashyyyk_rryatt_trail')"
:active="kashyyyk"
/>
<PlanetSwitch
label="South Dungeons"
sub-label="Hracca Glade, Bocctyyy"
:planet="getPlanet('kashyyyk_south_dungeons')"
:active="kashyyyk"
/>
<label
class="mt-3"
style="font-style: italic; opacity: 0.8; font-size: 10px"
>Note: See Space Zones for Kashyyyk Space</label
>
</CCardBody>
</CCard>
</CCol>
<CCol xl="3" lg="4" sm="6" class="mb-3">
<CCard style="height: 100%">
<CCardHeader>
<CRow>
<CCol>
<h4>Space Zones</h4>
</CCol>
<CCol class="text-right">
<label
style="
vertical-align: top;
margin-right: 5px;
margin-top: 3px;
"
><strong>Enabled:</strong></label
>
<CSwitch
shape="pill"
color="primary"
:checked="space"
@update:checked="() => (space = !space)"
/>
</CCol>
</CRow>
</CCardHeader>
<CCardBody>
<PlanetSwitch
label="Corellian System"
sub-label="Corellia, Talus"
:planet="getPlanet('space_corellia')"
:active="space"
/>
<PlanetSwitch
label="Naboo System"
sub-label="Naboo, Rori"
:planet="getPlanet('space_naboo')"
:active="space"
/>
<PlanetSwitch
label="Tatoo System"
:planet="getPlanet('space_tatooine')"
:active="space"
/>
<PlanetSwitch
label="Karthak System"
sub-label="Lok"
:planet="getPlanet('space_lok')"
:active="space"
/>
<PlanetSwitch
label="Dantooine System"
:planet="getPlanet('space_dantooine')"
:active="space"
/>
<PlanetSwitch
label="Dathomir System"
:planet="getPlanet('space_dathomir')"
:active="space"
/>
<PlanetSwitch
label="Yavin System"
:planet="getPlanet('space_yavin4')"
:active="space"
/>
<PlanetSwitch
label="Endor System"
:planet="getPlanet('space_endor')"
:active="space"
/>
<PlanetSwitch
label="Kashyyyk System"
:planet="getPlanet('space_kashyyyk')"
:active="space"
/>
<PlanetSwitch
label="Nova Orion Station"
:planet="getPlanet('space_nova_orion')"
:active="space"
/>
<PlanetSwitch
label="Kessel System"
sub-level="Ace Pilots"
:planet="getPlanet('space_light1')"
:active="space"
/>
<PlanetSwitch
label="Deep Space"
sub-label="PvP Space Zone"
:planet="getPlanet('space_heavy1')"
:active="space"
/>
</CCardBody>
</CCard>
</CCol>
<CCol xl="3" lg="4" sm="6" class="mb-3">
<CCard style="height: 100%">
<CCardHeader>
<CRow>
<CCol>
<h4>New Player Experience (NPE)</h4>
</CCol>
<CCol class="text-right">
<label
style="
vertical-align: top;
margin-right: 5px;
margin-top: 3px;
"
><strong>Enabled:</strong></label
>
<CSwitch
shape="pill"
color="primary"
:checked="tutorial"
@update:checked="() => (tutorial = !tutorial)"
/>
</CCol>
</CRow>
</CCardHeader>
<CCardBody>
<label
style="vertical-align: top; margin-right: 15px; margin-top: 3px"
><strong>New Player Tutorial:</strong></label
>
<CSwitch
shape="pill"
color="primary"
label-off="OFF"
label-on="ON"
:checked="
getPropertyValue('centralServer.newbieTutorialEnabled') &&
tutorial
"
@update:checked="
(e) => {
updateProperty({
property: 'centralServer.newbieTutorialEnabled',
value: e,
});
npeStatus = e;
tutorial = e;
}
"
/>
<PlanetSwitch
label="Imperial Space Station"
sub-label="Med Bay (Starting Point) &amp; Hangar"
:planet="getPlanet('tutorial')"
:active="tutorial && npeStatus"
:disabled="!npeStatus"
/>
<PlanetSwitch
label="Millenium Falcon"
sub-label="First Instance"
:planet="getPlanet('space_npe_falcon')"
:active="tutorial && npeStatus"
:disabled="!npeStatus"
/>
<PlanetSwitch
label="Millenium Falcon 2"
sub-label="Second Instance (Not Required)"
:planet="getPlanet('space_npe_falcon_2')"
:active="tutorial && npeStatus"
:disabled="!npeStatus"
/>
<PlanetSwitch
label="Millenium Falcon 3"
sub-label="Third Instance (Not Required)"
:planet="getPlanet('space_npe_falcon_3')"
:active="tutorial && npeStatus"
:disabled="!npeStatus"
/>
<PlanetSwitch
label="Ord Mantell System"
:planet="getPlanet('space_ord_mantell')"
:active="tutorial && npeStatus"
:disabled="!npeStatus"
/>
</CCardBody>
</CCard>
</CCol>
<CCol xl="3" lg="4" sm="6" class="mb-3">
<CCard style="height: 100%">
<CCardHeader>
<CRow>
<CCol>
<h4>Instances</h4>
</CCol>
<CCol class="text-right">
<label
style="
vertical-align: top;
margin-right: 5px;
margin-top: 3px;
"
><strong>Enabled:</strong></label
>
<CSwitch
shape="pill"
color="primary"
:checked="instances"
@update:checked="() => (instances = !instances)"
/>
</CCol>
</CRow>
</CCardHeader>
<CCardBody>
<PlanetSwitch
label="Adventure 1"
sub-label="Heroic: Tusken King"
:planet="getPlanet('adventure1')"
:active="instances"
/>
<PlanetSwitch
label="Adventure 2"
sub-label="Heroic: Echo Base"
:planet="getPlanet('adventure2')"
:active="instances"
/>
<PlanetSwitch
label="Dungeons"
sub-label="IG-88, Axkva Min, Exar Kun, Imperial Star Destroyer, Meatlump Hideout, Tansaari Point Station, Corellian Corvette"
:planet="getPlanet('adventure1')"
:active="instances"
/>
</CCardBody>
</CCard>
</CCol>
</CRow>
</div>
</template>
<script>
import SettingsMixin from '@/views/settings/mixins/settings-mixin';
import PlanetSwitch from '@/components/PlanetSwitch.vue';
export default {
name: 'PlanetsTab',
mixins: [SettingsMixin],
components: { PlanetSwitch },
};
</script>

View File

@@ -0,0 +1,391 @@
<template>
<div>
<CRow class="mt-3">
<CCol class="col-xl-4 col-lg-6">
<SettingsCard title="General Settings">
<TimerInput
label="Idle Logout Time (seconds):"
unit="seconds"
:value="getPropertyValue('gameServer.idleLogoutTimeSec')"
@update="
(e) => {
updateProperty({
property: 'gameServer.idleLogoutTimeSec',
value: e,
});
}
"
:horizontal="{ label: 'col-sm-6', input: 'col-sm-6' }"
/>
<CInput
label="Max. Galactic Reserve Deposit (billions):"
v-integer-only
type="number"
:value="
getPropertyValue('gameServer.maxGalacticReserveDepositBillion')
"
@update="
(e) => {
updateProperty({
property: 'gameServer.maxGalacticReserveDepositBillion',
value: e,
});
}
"
:horizontal="{ label: 'col-sm-6', input: 'col-sm-6' }"
/>
<CInput
label="Maximum Credits:"
v-integer-only
type="number"
max="2147483647"
:value="getPropertyValue('gameServer.maxMoney')"
@update="
(e) => {
updateProperty({
property: 'gameServer.maxMoney',
value: e,
});
}
"
:horizontal="{ label: 'col-sm-6', input: 'col-sm-6' }"
/>
<CInput
label="Max. Credit Transfer:"
v-integer-only
type="number"
:value="getPropertyValue('gameServer.maxMoneyTransfer')"
@update="
(e) => {
updateProperty({
property: 'gameServer.maxMoneyTransfer',
value: e,
});
}
"
:horizontal="{ label: 'col-sm-6', input: 'col-sm-6' }"
/>
<Toggle
class="server-config"
label="Do Not Validate Names:"
:checked="gameServer.nameValidationAcceptAll"
property="gameServer.nameValidationAcceptAll"
@update:checked="updateProperty"
/>
<Toggle
class="server-config"
label="Player Travel:"
:checked="!gameServer.disableTravel"
property="gameServer.disableTravel"
@update:checked="updateProperty"
inverse
/>
<Toggle
class="server-config"
label="Player Mounts:"
:checked="gameServer.mountsEnabled"
property="gameServer.mountsEnabled"
@update:checked="updateProperty"
/>
<Toggle
class="server-config"
label="Player Ships:"
:checked="gameServer.shipsEnabled"
property="gameServer.shipsEnabled"
@update:checked="updateProperty"
/>
<Toggle
class="server-config"
label="Player Missions:"
:checked="!gameServer.disableMissions"
property="gameServer.disableMissions"
@update:checked="updateProperty"
inverse
/>
<CInput
label="Mission Terminal Experience Award Limit (Daily):"
:value="getPropertyValue('custom.dailyMissionXpLimit')"
append="x"
type="number"
v-integer-only
@update="
(e) => {
updateProperty({
property: 'custom.dailyMissionXpLimit',
value: e,
});
}
"
:horizontal="{ label: 'col-sm-9', input: 'col-sm-3' }"
/>
<CInput
label="ITV Minimum Level Requirement:"
:value="getPropertyValue('characterBuilder.itvMinUsageLevel')"
type="number"
v-integer-only
@update="
(e) => {
updateProperty({
property: 'characterBuilder.itvMinUsageLevel',
value: e,
});
}
"
:horizontal="{ label: 'col-sm-6', input: 'col-sm-6' }"
/>
<CInput
label="Experience Multiplier:"
:value="getPropertyValue('gameServer.xpMultiplier')"
@update="
(e) => {
updateProperty({
property: 'gameServer.xpMultiplier',
value: e,
});
}
"
:horizontal="{ label: 'col-sm-6', input: 'col-sm-6' }"
/>
<CInput
label="GCW Experience Bonus:"
:value="getPropertyValue('gameServer.gcwXpBonus')"
@update="
(e) => {
updateProperty({
property: 'gameServer.gcwXpBonus',
value: e,
});
}
"
:horizontal="{ label: 'col-sm-6', input: 'col-sm-6' }"
/>
<CInput
label="Crafting Experience Chance:"
:value="getPropertyValue('gameServer.craftingXpChance')"
@update="
(e) => {
updateProperty({
property: 'gameServer.craftingXpChance',
value: e,
});
}
"
:horizontal="{ label: 'col-sm-6', input: 'col-sm-6' }"
/>
</SettingsCard>
</CCol>
<CCol class="col-xl-4 col-lg-6">
<SettingsCard title="Attributes">
<Toggle
class="server-config"
label="Grant Elder Buff on Login:"
:checked="custom.grantElderBuff"
property="custom.grantElderBuff"
@update:checked="updateProperty"
/>
<CInput
label="Armor Damage Reduction:"
append="%"
type="number"
v-float-only
:value="getPropertyValue('gameServer.armorDamageReduction')"
@update="
(e) => {
updateProperty({
property: 'gameServer.armorDamageReduction',
value: e,
});
}
"
:horizontal="{ label: 'col-sm-6', input: 'col-sm-6' }"
/>
<CInput
label="Action Regeneration Rate:"
type="number"
v-float-only
:value="getPropertyValue('gameServer.defaultActionRegen')"
@update="
(e) => {
updateProperty({
property: 'gameServer.defaultActionRegen',
value: e,
});
}
"
:horizontal="{ label: 'col-sm-6', input: 'col-sm-6' }"
/>
<CInput
label="Health Regeneration Rate:"
type="number"
v-float-only
:value="getPropertyValue('gameServer.defaultHealthRegen')"
@update="
(e) => {
updateProperty({
property: 'gameServer.defaultHealthRegen',
value: e,
});
}
"
:horizontal="{ label: 'col-sm-6', input: 'col-sm-6' }"
/>
<CInput
label="Max. Item Attribute Bonus:"
type="number"
v-integer-only
:value="getPropertyValue('gameServer.maxItemAttribBonus')"
@update="
(e) => {
updateProperty({
property: 'gameServer.maxItemAttribBonus',
value: e,
});
}
"
:horizontal="{ label: 'col-sm-6', input: 'col-sm-6' }"
/>
<CInput
label="Max. Object Skill Mod Bonus:"
type="number"
v-integer-only
:value="getPropertyValue('gameServer.maxObjectSkillModBonus')"
@update="
(e) => {
updateProperty({
property: 'gameServer.maxObjectSkillModBonus',
value: e,
});
}
"
:horizontal="{ label: 'col-sm-6', input: 'col-sm-6' }"
/>
<CInput
label="Max. Socket Skill Mod Bonus:"
type="number"
v-integer-only
:value="getPropertyValue('gameServer.maxSocketSkillModBonus')"
@update="
(e) => {
updateProperty({
property: 'gameServer.maxSocketSkillModBonus',
value: e,
});
}
"
:horizontal="{ label: 'col-sm-6', input: 'col-sm-6' }"
/>
<CInput
label="Max. Total Attribute Bonus:"
type="number"
v-integer-only
:value="getPropertyValue('gameServer.maxTotalAttribBonus')"
@update="
(e) => {
updateProperty({
property: 'gameServer.maxTotalAttribBonus',
value: e,
});
}
"
:horizontal="{ label: 'col-sm-6', input: 'col-sm-6' }"
/>
</SettingsCard>
</CCol>
<CCol class="col-xl-4 col-lg-6">
<SettingsCard title="Player Rewards">
<h5>Game Updates</h5>
<Toggle
class="server-config"
label="Award Flash Speeder:"
:checked="gameServer.flashSpeederReward"
property="gameServer.flashSpeederReward"
@update:checked="updateProperty"
/>
<CSelect
label="Award CU Plaque(s):"
:value="gameServer.combatUpgradeReward"
property="gameServer.combatUpgradeReward"
:options="[
{ label: 'Silver Plaque Only', value: 1 },
{ label: 'Silver & Gold Plaque', value: 2 },
]"
@update="updateProperty"
:horizontal="{ label: 'col-sm-6', input: 'col-sm-6' }"
/>
<h5>Veteran Rewards</h5>
<Toggle
class="server-config"
label="Veteran Rewards:"
:checked="gameServer.enableVeteranRewards"
property="gameServer.enableVeteranRewards"
@update:checked="updateProperty"
/>
<Toggle
class="server-config"
label="New Veteran Rewards:"
:checked="gameServer.enableNewVeteranRewards"
property="gameServer.enableNewVeteranRewards"
@update:checked="updateProperty"
/>
<Toggle
class="server-config"
label="Allow Account Age Override:"
:checked="gameServer.veteranDebugEnableOverrideAccountAge"
property="gameServer.veteranDebugEnableOverrideAccountAge"
@update:checked="updateProperty"
/>
<Toggle
class="server-config"
label="Trigger All Awards:"
:checked="gameServer.veteranDebugTriggerAll"
property="gameServer.veteranDebugTriggerAll"
@update:checked="updateProperty"
/>
<h5 class="spacer">Anniversary</h5>
<Toggle
class="server-config"
label="One-Year Anniversary:"
:checked="gameServer.enableOneYearAnniversary"
property="gameServer.enableOneYearAnniversary"
@update:checked="updateProperty"
/>
<h5 class="spacer">New Player Recruiting</h5>
<CInput
label="Buddy Point Time Bonus:"
append="Days"
type="number"
v-float-only
:value="getPropertyValue('gameServer.buddyPointTimeBonus')"
@update="
(e) => {
updateProperty({
property: 'gameServer.buddyPointTimeBonus',
value: e,
});
}
"
:horizontal="{ label: 'col-sm-6', input: 'col-sm-6' }"
/>
</SettingsCard>
</CCol>
</CRow>
</div>
</template>
<style lang="scss">
h5.spacer {
margin-top: 25px;
}
.general-config {
label:first-of-type {
width: 185px;
}
}
</style>
<script>
import SettingsMixin from '@/views/settings/mixins/settings-mixin';
export default {
name: 'PlayersTab',
mixins: [SettingsMixin],
};
</script>

View File

@@ -0,0 +1,90 @@
<template>
<div>
<CRow class="mt-3">
<CCol class="col-xl-4 col-sm-6">
<SettingsCard title="General">
<CInput
:value="getPropertyValue('gameServer.houseItemLimitMultiplier')"
label="House Item Limit Multiplier:"
type="number"
v-integer-only
@update="
(e) => {
updateProperty({
property: 'gameServer.houseItemLimitMultiplier',
value: e,
});
}
"
:horizontal="{ label: 'col-sm-6', input: 'col-sm-6' }"
/>
<CInput
:value="getPropertyValue('gameServer.maxHouseItemLimit')"
label="House Item Limit:"
type="number"
v-integer-only
@update="
(e) => {
updateProperty({
property: 'gameServer.maxHouseItemLimit',
value: e,
});
}
"
:horizontal="{ label: 'col-sm-6', input: 'col-sm-6' }"
/>
</SettingsCard>
</CCol>
<CCol class="col-xl-4 col-sm-6">
<SettingsCard title="Harvesters &amp; Factories">
<h5>Harvesters</h5>
<Toggle
class="resource-config"
label="Deactivate Damaged Harvesters:"
:checked="gameServer.deactivateHarvesterIfDamaged"
property="gameServer.deactivateHarvesterIfDamaged"
@update:checked="updateProperty"
/>
<CInput
:value="
getPropertyValue('gameServer.harvesterExtractionRateMultiplier')
"
append="x"
label="Harvester Extraction Rate:"
@update="
(e) => {
updateProperty({
property: 'gameServer.harvesterExtractionRateMultiplier',
value: e,
});
}
"
:horizontal="{ label: 'col-sm-6', input: 'col-sm-6' }"
/>
<h5>Factories</h5>
<CInput
:value="getPropertyValue('gameServer.manufactureTimeOverride')"
label="Manufacturing Time Override:"
@update="
(e) => {
updateProperty({
property: 'gameServer.manufactureTimeOverride',
value: e,
});
}
"
:horizontal="{ label: 'col-sm-6', input: 'col-sm-6' }"
/>
</SettingsCard>
</CCol>
</CRow>
</div>
</template>
<script>
import SettingsMixin from '@/views/settings/mixins/settings-mixin';
export default {
name: 'StructuresTab',
mixins: [SettingsMixin],
};
</script>

View File

@@ -0,0 +1,502 @@
<template>
<div>
<CRow>
<CCol sm="6" lg="3">
<CWidgetProgress footer="Lorem ipsum dolor sit amet enim.">
<div class="h4 m-0">89.9%</div>
<div class="card-header-actions">
<a
href="https://coreui.io/vue/docs/components/widgets"
class="card-header-action position-absolute"
style="right:5px; top:5px"
rel="noreferrer noopener"
target="_blank"
>
<small class="text-muted">docs</small>
</a>
</div>
<div>Lorem ipsum...</div>
<CProgress
color="gradient-success"
:value="25"
class="progress-xs my-3 mb-0"
/>
</CWidgetProgress>
</CCol>
<CCol sm="6" lg="3">
<CWidgetProgress
header="12.124"
text="Lorem ipsum..."
footer="Lorem ipsum dolor sit amet enim."
color="gradient-info"
:value="25"
/>
</CCol>
<CCol sm="6" lg="3">
<CWidgetProgress
header="$98.111,00"
text="Lorem ipsum..."
footer="Lorem ipsum dolor sit amet enim."
color="gradient-warning"
:value="25"
/>
</CCol>
<CCol sm="6" lg="3">
<CWidgetProgress
header="2 TB"
text="Lorem ipsum..."
footer="Lorem ipsum dolor sit amet enim."
color="gradient-danger"
:value="25"
/>
</CCol>
</CRow>
<CRow>
<CCol sm="6" lg="3">
<CWidgetProgress
header="89.9%"
text="Lorem ipsum..."
footer="Lorem ipsum dolor sit amet enim."
color="gradient-success"
inverse :value="25"
/>
</CCol>
<CCol sm="6" lg="3">
<CWidgetProgress
header="12.124"
text="Lorem ipsum..."
footer="Lorem ipsum dolor sit amet enim."
color="gradient-info"
inverse
:value="25"
/>
</CCol>
<CCol sm="6" lg="3">
<CWidgetProgress
header="$98.111,00"
text="Lorem ipsum..."
footer="Lorem ipsum dolor sit amet enim."
color="gradient-warning"
inverse
:value="25"
/>
</CCol>
<CCol sm="6" lg="3">
<CWidgetProgress
header="2 TB"
text="Lorem ipsum..."
footer="Lorem ipsum dolor sit amet enim."
color="gradient-danger"
inverse
:value="25"
/>
</CCol>
</CRow>
<CRow>
<CCol col="12" sm="6" lg="3">
<CWidgetIcon
header="$1.999,50"
text="Income"
color="gradient-primary"
>
<CIcon name="cil-settings" width="24"/>
</CWidgetIcon>
</CCol>
<CCol col="12" sm="6" lg="3">
<CWidgetIcon
header="$1.999,50"
text="Income"
color="gradient-info"
>
<CIcon name="cil-laptop" width="24"/>
</CWidgetIcon>
</CCol>
<CCol col="12" sm="6" lg="3">
<CWidgetIcon
header="$1.999,50"
text="Income"
color="gradient-warning"
>
<CIcon name="cil-moon" width="24"/>
</CWidgetIcon>
</CCol>
<CCol col="12" sm="6" lg="3">
<CWidgetIcon
header="$1.999,50"
text="Income"
color="gradient-danger"
>
<CIcon name="cil-bell" width="24"/>
</CWidgetIcon>
</CCol>
</CRow>
<CRow>
<CCol col="12" sm="6" lg="3">
<CWidgetIcon
header="$1.999,50"
text="Income"
color="gradient-primary"
:icon-padding="false"
>
<CIcon name="cil-settings" width="24"/>
</CWidgetIcon>
</CCol>
<CCol col="12" sm="6" lg="3">
<CWidgetIcon
header="$1.999,50"
text="Income"
color="gradient-info"
:icon-padding="false"
>
<CIcon name="cil-laptop" width="24"/>
</CWidgetIcon>
</CCol>
<CCol col="12" sm="6" lg="3">
<CWidgetIcon
header="$1.999,50"
text="Income"
color="gradient-warning"
:icon-padding="false"
>
<CIcon name="cil-moon" width="24"/>
</CWidgetIcon>
</CCol>
<CCol col="12" sm="6" lg="3">
<CWidgetIcon
header="$1.999,50"
text="Income"
color="gradient-danger"
:icon-padding="false"
>
<CIcon name="cil-bell" width="24"/>
</CWidgetIcon>
</CCol>
</CRow>
<CRow>
<CCol col="12" sm="6" lg="4">
<CWidgetIcon
header="$1.999,50"
text="Income"
color="gradient-primary"
:icon-padding="false"
>
<CIcon name="cil-settings" class="mx-5 " width="24"/>
</CWidgetIcon>
</CCol>
<CCol col="12" sm="6" lg="4">
<CWidgetIcon
header="$1.999,50"
text="Income"
color="gradient-info"
:icon-padding="false"
>
<CIcon name="cil-laptop" class="mx-5 " width="24"/>
</CWidgetIcon>
</CCol>
<CCol col="12" sm="6" lg="4">
<CWidgetIcon
header="$1.999,50"
text="Income"
color="gradient-warning"
:icon-padding="false"
>
<CIcon name="cil-moon" class="mx-5 " width="24"/>
<template #footer>
<CCardFooter class="px-3 py-2">
<CLink
class="font-weight-bold font-xs text-muted d-flex justify-content-between"
href="https://coreui.io/"
target="_blank"
>
View more
<CIcon name="cil-arrow-right" width="16"/>
</CLink>
</CCardFooter>
</template>
</CWidgetIcon>
</CCol>
</CRow>
<!-- <CRow>
<CCol col="12" sm="6" lg="4">
<CWidgetIcon
header="$1.999,50"
text="Income"
color="gradient-primary"
:icon-padding="false"
link="#"
>
<CIcon name="cil-settings" class="mx-5 " width="24"/>
</CWidgetIcon>
</CCol>
<CCol col="12" sm="6" lg="4">
<CWidgetIcon
header="$1.999,50"
text="Income"
color="gradient-info"
:icon-padding="false"
link="#"
>
<CIcon name="cil-laptop" class="mx-5 " width="24"/>
</CWidgetIcon>
</CCol>
<CCol col="12" sm="6" lg="4">
<CWidgetIcon
header="$1.999,50"
text="Income"
color="gradient-warning"
:icon-padding="false"
link="#"
>
<CIcon name="cil-moon" class="mx-5" width="24"/>
</CWidgetIcon>
</CCol>
</CRow> -->
<WidgetsBrand noCharts/>
<WidgetsBrand/>
<CCardGroup class="mb-4">
<CWidgetProgressIcon
header="87.500"
text="Visitors"
color="gradient-info"
>
<CIcon name="cil-people" height="36"/>
</CWidgetProgressIcon>
<CWidgetProgressIcon
header="385"
text="New Clients"
color="gradient-success"
>
<CIcon name="cil-userFollow" height="36"/>
</CWidgetProgressIcon>
<CWidgetProgressIcon
header="1238"
text="Products sold"
color="gradient-warning"
>
<CIcon name="cil-basket" height="36"/>
</CWidgetProgressIcon>
<CWidgetProgressIcon
header="28%"
text="Returning Visitors"
>
<CIcon name="cil-chartPie" height="36"/>
</CWidgetProgressIcon>
<CWidgetProgressIcon
header="5:34:11"
text="Avg. Time"
color="gradient-danger"
>
<CIcon name="cil-speedometer" height="36"/>
</CWidgetProgressIcon>
</CCardGroup>
<CCardGroup class="mb-4">
<CWidgetProgressIcon
header="87.500"
text="Visitors"
color="gradient-info"
inverse
>
<CIcon name="cil-people" height="36"/>
</CWidgetProgressIcon>
<CWidgetProgressIcon
header="385"
text="New Clients"
color="gradient-success"
inverse
>
<CIcon name="cil-userFollow" height="36"/>
</CWidgetProgressIcon>
<CWidgetProgressIcon
header="1238"
text="Products sold"
color="gradient-warning"
inverse
>
<CIcon name="cil-basket" height="36"/>
</CWidgetProgressIcon>
<CWidgetProgressIcon
header="28%"
text="Returning Visitors"
color="gradient-primary"
inverse
>
<CIcon name="cil-chartPie" height="36"/>
</CWidgetProgressIcon>
<CWidgetProgressIcon
header="5:34:11"
text="Avg. Time"
color="gradient-danger"
inverse
>
<CIcon name="cil-speedometer" height="36"/>
</CWidgetProgressIcon>
</CCardGroup>
<CRow>
<CCol sm="6" md="2">
<CWidgetProgressIcon
header="87.500"
text="Visitors"
color="gradient-info"
>
<CIcon name="cil-people" height="36"/>
</CWidgetProgressIcon>
</CCol>
<CCol sm="6" md="2">
<CWidgetProgressIcon
header="385"
text="New Clients"
color="gradient-success"
>
<CIcon name="cil-userFollow" height="36"/>
</CWidgetProgressIcon>
</CCol>
<CCol sm="6" md="2">
<CWidgetProgressIcon
header="1238"
text="Products sold"
color="gradient-warning"
>
<CIcon name="cil-basket" height="36"/>
</CWidgetProgressIcon>
</CCol>
<CCol sm="6" md="2">
<CWidgetProgressIcon
header="28%"
text="Returning Visitors"
color="gradient-primary"
>
<CIcon name="cil-chartPie" height="36"/>
</CWidgetProgressIcon>
</CCol>
<CCol sm="6" md="2">
<CWidgetProgressIcon
header="5:34:11"
text="Avg. Time"
color="gradient-danger"
>
<CIcon name="cil-speedometer" height="36"/>
</CWidgetProgressIcon>
</CCol>
<CCol sm="6" md="2">
<CWidgetProgressIcon
header="972"
text="comments"
color="gradient-info"
>
<CIcon name="cil-speech" height="36"/>
</CWidgetProgressIcon>
</CCol>
</CRow>
<CRow>
<CCol sm="6" md="2">
<CWidgetProgressIcon
header="87.500"
text="Visitors"
color="gradient-info"
inverse
>
<CIcon name="cil-people" height="36"/>
</CWidgetProgressIcon>
</CCol>
<CCol sm="6" md="2">
<CWidgetProgressIcon
header="385"
text="New Clients"
color="gradient-success"
inverse
>
<CIcon name="cil-userFollow" height="36"/>
</CWidgetProgressIcon>
</CCol>
<CCol sm="6" md="2">
<CWidgetProgressIcon
header="1238"
text="Products sold"
color="gradient-warning"
inverse
>
<CIcon name="cil-basket" height="36"/>
</CWidgetProgressIcon>
</CCol>
<CCol sm="6" md="2">
<CWidgetProgressIcon
header="28%"
text="Returning Visitors"
color="gradient-primary"
inverse
>
<CIcon name="cil-chartPie" height="36"/>
</CWidgetProgressIcon>
</CCol>
<CCol sm="6" md="2">
<CWidgetProgressIcon
header="5:34:11"
text="Avg. Time"
color="gradient-danger"
inverse
>
<CIcon name="cil-speedometer" height="36"/>
</CWidgetProgressIcon>
</CCol>
<CCol sm="6" md="2">
<CWidgetProgressIcon
header="972"
text="comments"
color="gradient-info"
inverse
>
<CIcon name="cil-speech" height="36"/>
</CWidgetProgressIcon>
</CCol>
</CRow>
<WidgetsDropdown/>
<CRow>
<CCol sm="4" lg="2">
<CWidgetSimple header="title" text="1,123">
<CChartLineSimple style="height:40px" border-color="danger"/>
</CWidgetSimple>
</CCol>
<CCol sm="4" lg="2">
<CWidgetSimple header="title" text="1,123">
<CChartLineSimple style="height:40px" border-color="primary"/>
</CWidgetSimple>
</CCol>
<CCol sm="4" lg="2">
<CWidgetSimple header="title" text="1,123">
<CChartLineSimple style="height:40px" border-color="success"/>
</CWidgetSimple>
</CCol>
<CCol sm="4" lg="2">
<CWidgetSimple header="title" text="1,123">
<CChartBarSimple style="height:40px" background-color="danger"/>
</CWidgetSimple>
</CCol>
<CCol sm="4" lg="2">
<CWidgetSimple header="title" text="1,123">
<CChartBarSimple style="height:40px" background-color="primary"/>
</CWidgetSimple>
</CCol>
<CCol sm="4" lg="2">
<CWidgetSimple header="title" text="1,123">
<CChartBarSimple style="height:40px" background-color="success"/>
</CWidgetSimple>
</CCol>
</CRow>
</div>
</template>
<script>
import WidgetsBrand from './WidgetsBrand'
import WidgetsDropdown from './WidgetsDropdown'
import { CChartLineSimple, CChartBarSimple } from '../charts/index.js'
export default {
name: 'Widgets',
components: {
CChartLineSimple,
CChartBarSimple,
WidgetsBrand,
WidgetsDropdown
}
}
</script>

View File

@@ -0,0 +1,138 @@
<template>
<CRow>
<CCol sm="6" lg="3">
<CWidgetDropdown color="primary" header="1,134" text="Players Online">
<template #default>
<CDropdown
color="transparent p-0"
placement="bottom-end"
>
<template #toggler-content>
<CIcon name="cil-settings"/>
</template>
<CDropdownItem>Action</CDropdownItem>
<CDropdownItem>Another action</CDropdownItem>
<CDropdownItem>Something else here...</CDropdownItem>
<CDropdownItem disabled>Disabled action</CDropdownItem>
</CDropdown>
</template>
<template #footer>
<CChartLineSimple
pointed
class="mt-3 mx-3"
style="height:70px"
:data-points="[65, 59, 84, 84, 51, 55, 40]"
point-hover-background-color="primary"
label="Members"
labels="months"
/>
</template>
</CWidgetDropdown>
</CCol>
<CCol sm="6" lg="3">
<CWidgetDropdown color="info" header="9.823" text="Total Logins">
<template #default>
<CDropdown
color="transparent p-0"
placement="bottom-end"
:caret="false"
>
<template #toggler-content>
<CIcon name="cil-location-pin"/>
</template>
<CDropdownItem>Action</CDropdownItem>
<CDropdownItem>Another action</CDropdownItem>
<CDropdownItem>Something else here...</CDropdownItem>
<CDropdownItem disabled>Disabled action</CDropdownItem>
</CDropdown>
</template>
<template #footer>
<CChartLineSimple
pointed
class="mt-3 mx-3"
style="height:70px"
:data-points="[1, 18, 9, 17, 34, 22, 11]"
point-hover-background-color="info"
:options="{ elements: { line: { tension: 0.00001 }}}"
label="Members"
labels="months"
/>
</template>
</CWidgetDropdown>
</CCol>
<CCol sm="6" lg="3">
<CWidgetDropdown
color="warning"
header="3,984"
text="Active Players"
>
<template #default>
<CDropdown
color="transparent p-0"
placement="bottom-end"
>
<template #toggler-content>
<CIcon name="cil-settings"/>
</template>
<CDropdownItem>Action</CDropdownItem>
<CDropdownItem>Another action</CDropdownItem>
<CDropdownItem>Something else here...</CDropdownItem>
<CDropdownItem disabled>Disabled action</CDropdownItem>
</CDropdown>
</template>
<template #footer>
<CChartLineSimple
class="mt-3"
style="height:70px"
background-color="rgba(255,255,255,.2)"
:data-points="[78, 81, 80, 45, 34, 12, 40]"
:options="{ elements: { line: { borderWidth: 2.5 }}}"
point-hover-background-color="warning"
label="Members"
labels="months"
/>
</template>
</CWidgetDropdown>
</CCol>
<CCol sm="6" lg="3">
<CWidgetDropdown
color="danger"
header="2,845"
text="Inactive Players"
>
<template #default>
<CDropdown
color="transparent p-0"
placement="bottom-end"
>
<template #toggler-content>
<CIcon name="cil-settings"/>
</template>
<CDropdownItem>Action</CDropdownItem>
<CDropdownItem>Another action</CDropdownItem>
<CDropdownItem>Something else here...</CDropdownItem>
<CDropdownItem disabled>Disabled action</CDropdownItem>
</CDropdown>
</template>
<template #footer>
<CChartBarSimple
class="mt-3 mx-3"
style="height:70px"
background-color="rgb(250, 152, 152)"
label="Members"
labels="months"
/>
</template>
</CWidgetDropdown>
</CCol>
</CRow>
</template>
<script>
import { CChartLineSimple, CChartBarSimple } from '../charts/index.js'
export default {
name: 'WidgetsDropdown',
components: { CChartLineSimple, CChartBarSimple }
}
</script>

20
vue.config.js Normal file
View File

@@ -0,0 +1,20 @@
module.exports = {
devServer: {
port: 9000,
proxy: {
'^/api': {
target: 'https://localhost:8080',
changeOrigin: true,
},
},
},
lintOnSave: false,
runtimeCompiler: true,
configureWebpack: {
//Necessary to run npm link https://webpack.js.org/configuration/resolve/#resolve-symlinks
resolve: {
symlinks: false,
},
},
transpileDependencies: ['@coreui/utils', '@coreui/vue'],
};

11
workspace.code-workspace Normal file
View File

@@ -0,0 +1,11 @@
{
"folders": [
{
"path": "."
}
],
"settings": {
"editor.formatOnSave": true,
"editor.defaultFormatter": "esbenp.prettier-vscode"
}
}

12049
yarn.lock Normal file

File diff suppressed because it is too large Load Diff